Reparenting in React.js - reactjs

I wanted to know if i can move the child component from one element to another element without having to recreate the component.
Referring the case in the given attached image.
gif image of behaviour
Is it possible to move the <Components Two/> in <parent one> to <parent two> without running the expensive operations within the <Components Two/> again ? ie not recreating the component again. Would useMemo make sense in here ?

You can try the library https://github.com/Paol-imi/react-reparenting. I have a view navigation use case, currently trying some experimenting with this.

Related

Alternative to Reactdom.render and unmountComponentAtNode in react18

Important note:
I am aware of createRoot and root.unmount()! Unfortunately (If I understand this correctly) they should be used just once in the application for mounting the react application.
Problem description:
In our app we have a modal component that is rendered dynamically and added to the body of the html via ReactDOM.render(). When this modal is hidden, we unmountComponentAtNode().
Unfortunately, after upgrading to react18, unmountComponentAtNode becomes deprecated and the new unmount is (in my understanding) for the root only. The same problem is about if I try to modify the ReactDOM.Render() for createRoot. Then we would have 2 roots in the app which is wrong.
What is the proper way to attach the modal to the body element (next to root!) and unmount it after it should be destroyed? The implementation is a little bit "weird" (partially in jsx, partially not...) and I would like to avoid refactoring the whole component as there will be a lot of refactoring already in the code... So I would like to focus on refactoring this component (into jsx one) later. Now I have to figure out only the rendering / unmounting. I have been thinking about using Portals, but anyway I have to create that elements somehow and render them into the DOM where portals does not help me a lot.
Calling the createRoot and then render on the root in this modal component fires an error You are calling ReactDOMClient.createRoot() on a container that has already been passed to createRoot() before. Instead, call root.render() on the existing root instead if you want to update it. which is obvious. But there is no "useRoot()" hook or anything like that. Should I store the returned object (root) in some context or somewhere to use it later? Or what should be the best option to call the render? :/
I know how I should do that with classical functional component... But maybe there is some way that I can just refactor a piece of the code instead of the whole component and all its usecases. Maybe there is something I am not aware of (there is definitely thousands of things I am not aware of :D) that should simplify my life...
function modal() {
return (
<div>
...
</div>
)
}
Modal.show = () => {
modalEl = document.createElement('div');
util.destroy(el) => {
ReactDOM.unmountComponentAtNode(el);
el.remove();
}
const childs = props.childs;
REactDOM.render(childs, modalEl);
}
When I was thinking about portals, I thought I will just rewrite the last line of ReactDOM.render to portal like createPortal(childs, modalEl), unfortunately this does not render anything (except modalEl, but no childs inside). The childs are of type ReactNode (using typescript) and they are not empty (because of ReactDOM.render works without any problem).

ReactJS wrap children, and descendents, see-through a component

I'm trying to find a good way to produce a layout control that wraps all it's DOM children, let's say in a div tag for simplicity. The basic approach is to use React.Children.map, but this is posing some problems with constructed lists of children via components -- it cannot see inside Components.
For example, say I have this structure, where the final DOM result should be a <ul> with several <li> elements. The Item* components themselves do not know they are in a list.
<WrapItems>
<ItemA/>
<ItemB/>
<ItemC/>
<ItemD/>
</WrapItems>
I can produce the DOM result I want by iterating the react children and wrapping them in a li. However, some of these items are shared between several controls, motivating me to create a common component.
<WrapItems>
<ItemA/>
<CommonItems/>
<ItemD/>
</WrapItems>
Where CommonItems ends up rendering:
<>
<ItemB/>
<ItemC/>
</>
The issue is that I cannot wrap ItemB and ItemC anymore, since React.Children will walk iterate the immediate children*.
Essentially I want CommonItems to be transparent and expose it's children directly to the WrapItems control, so that it can wrap them correctly. Is there a way to do this?
I've tried an approach where I replace the component with a useCommonItems function that returns an array of items instead. In some cases this can work, but in others it becomes a challenge, and a performance concern. Some of these parts are conditional, and the use approach forces them to all end up non-conditionally evaluated, along with all their use... functions in turn.
*Note, I'm aware that React.Children.map does not iterate over fragments, but I can solve that part by doing my own Children.map that descends into fragments. The issue in this question is about iterating over the children of components. The solution may be related, I'm not sure.

Real-Time use case of this.props.children

I have read many articles to find out the real time use case of this.props.children but i didn't find the answer that i am looking for.I know that this.props.children is used to access the data b/w the opening and closing tag of a component. But my question is why can't we add a prop to the component instead of writing data b/w opening and closing tag.
for Ex:
<Example>This is data<Example> //can be accessed as this.props.children
can be written as
<Example data="This is data"/> //can be accessed as this.props.data
Can somebody please explain me with a real-time example of where we can achieve a certain task by using only this.props.children?
For example if you have complicated children of a component:
<Card>
<div class='title'>Title</div>
<div class='content'>Content</div>
</Card>
It would be easier than if you write like:
<Card content={[<div class='title'>Title</div>, <....>]} />
Samething you can find here, for example in Drawer component of Material-UI here. Drawer is a component that slides from the left, it can contain anything, so using props.childrens.
While making an app, you want a parent component which will render anything in your component. The use cases which I can think of are:
When you want to open a different component depending upon the route change.
const App = ({ children }) => (
<div className="full-height">
{children}
</div>
);
When you want to have same styles throughout your app for generic elements such as body, head etc. You'll just have to apply on this component, e.g., in above example, the full-height will get applied everywhere in the app on top component. (Obviously there are other work arounds but this is always more clear)
For use cases where you want to expose your component (when component doesn't know children ahead of time) as libraries and props can vary a lot and complicates the rendering. Read this
Obviously you don't have to use it but it makes code more elegant and understandable.

Does React have keep-alive like Vue js?

I made a Todo list with React js. This web has List and Detail pages.
There is a list and 1 list has 10 items. When user scroll bottom, next page data will be loaded.
user click 40th item -> watch detail page (react-router) -> click back button
The main page scroll top of the page and get 1st page data again.
How to restore scroll position and datas without Ajax call?
When I used Vue js, i’ve used 'keep-alive' element.
Help me. Thank you :)
If you are working with react-router
Component can not be cached while going forward or back which lead to losing data and interaction while using Route
Component would be unmounted when Route was unmatched
After reading source code of Route we found that using children prop as a function could help to control rendering behavior.
Hiding instead of Removing would fix this issue.
I am already fixed it with my tools react-router-cache-route
Usage
Replace <Route> with <CacheRoute>
Replace <Switch> with <CacheSwitch>
If you want real <KeepAlive /> for React
I have my implementation react-activation
Online Demo
Usage
import KeepAlive, { AliveScope } from 'react-activation'
function App() {
const [show, setShow] = useState(true)
return (
<AliveScope>
<button onClick={() => setShow(show => !show)}>Toggle</button>
{show && (
<KeepAlive>
<Test />
</KeepAlive>
)}
</AliveScope>
)
}
The implementation principle is easy to say.
Because React will unload components that are in the intrinsic component hierarchy, we need to extract the components in <KeepAlive>, that is, their children props, and render them into a component that will not be unloaded.
Until now the awnser is no unfortunately. But there's a issue about it in React repository: https://github.com/facebook/react/issues/12039
keep-alive is really nice. Generally, if you want to preserve state, you look at using a Flux (Redux lib) design pattern to store your data in a global store. You can even add this to a single component use case and not use it anywhere else if you wish.
If you need to keep the component around you can look at hoisting the component up and adding a "display: none" style to the component there. This will preserve the Node and thus the component state along with it.
Worth noting also is the "key" field helps the React engine figure out what tree should be unmounted and what should be kept. If you have the same component and want to preserve its state across multiple usages, maintain the key value. Conversely, if you want to ensure an unmount, just change the key value.
While searching for the same, I found this library, which is said to be doing the same. Have not used though - https://www.npmjs.com/package/react-keep-alive

Rendering null in react element prevents me from using css's :empty selector

To better explain my question, I'll use an example:
Let's say I have two react elements, which contain one another. Lets call the container Box, and the child Stuff. Box just renders a div with className="box" which surrounds the children it is given. Stuff most of the time renders something, but its render function can return null when it decides there's nothing to render.
Here's the twist: if <Box> is empty, I don't want to show it at all. So I decided to use css3 selectors, and write something like
.box:empty {
display: none;
}
... which should work, except react renders a <noscript> tag, which prevents the browser from treating the parent .box element as empty...
Is there an elegant way around this? I'd like to keep the logic of determining emptiness inside of Stuff, and have Box just "look" at its contents and decide whether it wants to show anything or not.
UPDATE
This fiddle https://jsfiddle.net/69z2wepo/67543/ has an example of what I'm trying to do. Strangely, in that fiddle, it works, and react doesn't render <noscript> tags... why does it render <noscript>s in my code? In what cases does react choose to render <noscript>s?
Found the problem!
I was using an old version of react-css-modules (3.7.7). Upgrading to 4.1.0 fixed it.
Looks like this was a relatively recent fix, too:
https://github.com/gajus/react-css-modules/commit/a9c8de252d5464037090e155c431abfe9f671531

Resources