⚛️ Reparenting is now possible with React

栏目: IT技术 · 发布时间: 4年前

内容简介:I am designing an app similar toHow can I transfer a Card component after dragging? With React it seems quite easy. To change the Parent component of a Child component, the components have to be

Reparenting is now possible with React

How I implemented Reparenting with a few lines of code

May 23 ·7min read

⚛️ Reparenting is now possible with React

(This article is also available on the DEV community)

I am designing an app similar to Trello . On the main page, I want some vertical Lists and some Cards that can be dragged from one List to another.

How can I transfer a Card component after dragging? With React it seems quite easy. To change the Parent component of a Child component, the components have to be re-rendered with that Child in its new Parent.

⚛️ Reparenting is now possible with React

In the same way, I can transfer a <Card> into a new <List> .

I implement a first draft of the code and try it, I take a Card with the mouse and drag it between the various Lists. The transfer takes place, but, unfortunately, the Card component is unmounted, re-mounted, and loses its internal state .

Moreover the feedback from the drag animation isn’t so positive. When I perform some drags quickly in succession, the App slows down and for a few moments there is a considerable loss of frames .

In fact, the DOM elements of the Card are recreated from scratch and this is having a negative impact on performance . Also, one of the elements is a scrollable <div> that loses its scroll position, I guess other elements such as <video> and <audio> can have similar problems.

With some effort, I can redesign the App to use Card components without a local state, but in any case I cannot avoid that the DOM elements are recreated.

Is it possible to prevent the component from being re-mounted?

Well, if you are reading this article it is likely that the answer is positive :), but when I asked myself the question for the first time I did not find a definitive answer, probably because it was not there yet. Let’s continue with the story.

I start looking for an answer in the React repository on Github, maybe there is something useful in the issues section. I find there is a term for what I’m looking for, and it’s Reparenting .

“Reparenting aims to improve both the Developer and the User Experience.”

Some open issues confirm that React does not yet provide specific APIs to handle it, my hopes that something like React.transferComponent( ) exists quickly fade away.

An approach I discover is ReactDOM.unstable_renderSubtreeIntoContainer( ) , the name looks cool but the unstable tag and the fact that this API has been deprecated are enough to make me look for something else. Searches continue on Medium, Dev.to, and other platforms, the only possible solution seems to be the use of the Portals . A Tweet by Dan Abramov definitely convinces me to try them.

⚛️ Reparenting is now possible with React

The portals approach

I open the React documentation in the Portals section. I start reading the guide and doing some tests to get familiar with these APIs.

const element = document.createElement('div');const PortalComponent = ({children}) => {
  return ReactDOM.createPortal(children, element);
};

I know that I cannot move a component elsewhere in the App or it will be re-mounted, so every Child component must be part of the same Parent .

Should I use a portal for each Child? That way I could decide in which container element to render each of them. But how do I create containers? Do I have to write something like document.createElement('div') ? I could instead use ref to other components. Where do I render those components? Refs are empty initially, should I force a second render? I wanted each Parent to provide a different Context, How can I do that if I am forced to use only one Parent?…

What a mess, the more I try to implement it, the more forced the approach seems to me. It doesn’t give me the feeling of being very “reactive” , probably because portals have been designed for other purposes:

“Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.” — React docs.

This process is more related to the DOM, at the “React level” the Child is still part of the same Parent, not exactly what I am looking for.

The new solution

Maybe I’m looking for a solution in the wrong place, it is possible that, if it exists, it is more internal to React than I think.

What I know is that React represents my App with a tree of instances , where each instance corresponds to a component. When re-rendering a part of the App, its sub-tree is recreated and compared with the old one, so as to find the changes that have been made and update the DOM.

⚛️ Reparenting is now possible with React

The image is for illustrative purposes only

Due to the way this comparison is implemented, there is no method to make React aware of the transfer of a component. Indeed, If I try to re-render a Card component somewhere else, the result will be the unmounting of the component and the mounting of a new one.

How can I change this behavior? I could try to interact with the internal tree , find the instance of the Card that I want to transfer, and insert it in the new List. It might work! Before starting to design a solution, to avoid running into dead ends I impose some constraints that the final result must respect:

  • It must not rely on any unstable method
  • Reparenting must be able to work without redesigning the App
  • It must respect the philosophy and patterns of React

I have a solid starting point, now I have to understand how these react internals are actually implemented . I find out that starting from version 16, React rolled out a new implementation of that internal instances tree named Fiber . I read some articles about it to get a more complete picture, and when I think I have a fairly broad view on the topic, I start to browse the React source code in search of a solution.

After several days of testing and research, I finally have a first draft of code to try, inside a file named react-reparenting.js . I import it into my App, add a few lines of code, and… It works! The Card is not re-mounted and the goals that I have set for myself have all been respected.

This story can finally have a nice ending, I can continue the development of my App. Maybe, for the next obstacle that I will face, I will find a story like this to read.

The end of the story

This story ends with the publication of the package on Github and with the writing of this article. Before presenting it, I want to share with you what my vision is at the end of this project.

I strongly believe that Reparenting is not only a way of managing these situations, but The way , and I also believe that in the future React will implement it natively.

In my opinion, the reason why this feature has not yet been implemented is that the cases in which it is really necessary are not many. Often the components to be transferred are stateless and very simple, so it is an acceptable compromise to re-mount them since the difference in performance is almost zero, and there is no state or lifecycle to be interrupted.

I’m not saying that React will implement Reparenting as it has been implemented here, or that the APIs that will be provided will be similar to these, but I hope this package, thanks also to its simplicity, can lay the foundations for the use and diffusion of Reparenting.

“Unmounting one component and mounting another identical one is just a simple compromise that works in most cases. The component should always be transferred, without its lifecycle being interrupted.”

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

跨平台桌面应用开发:基于Electron与NW.js

跨平台桌面应用开发:基于Electron与NW.js

【丹】Paul B. Jensen / Goddy Zhao / 2018-3 / 99

《跨平台桌面应用开发:基于Electron与NW.js》是一本同时介绍 Electron和 NW.js的图书,这两者是目前流行的支持使用 HTML、CSS 和 JavaScript 进行桌面应用开发的框架。书中包含大量的编码示例,而且每个示例都是五脏俱全的实用应用,作者对示例中的关键代码都做了非常详细的解释和说明,可让读者通过实际的编码体会使用这两款框架开发桌面应用的切实感受。除此之外,在内容上,......一起来看看 《跨平台桌面应用开发:基于Electron与NW.js》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具