Multiple instances of same react component - reactjs

I want to add a react component, a comments feature, to a non-react site.
The site has a news page with infinite scrolling. Under each news story I want to include the react comments component. I plan to model it after the FB tutorial here: http://facebook.github.io/react/docs/tutorial.html
My question is, how do I dynamically mount each React component to a DOM story element? Basically, I want to have many instances of the same react comments component, but with each instance tied to a unique story (div).
I think I need to render the react component on the server side, where I can dynamically set the React.renderComponent. Any pointers/examples appreciated.

When the post is added you need to have your data and the target dom node (we'll call these variables data and el)
React.render(<MyComponent data={data} />, el);
Or without JSX
React.render(React.createElement(MyComponent, {data: data}), el);
To clean up:
React.unmountComponentAtNode(el);
For server side rendering you can do:
React.renderToString(React.createElement(MyComponent, {data: data}))
and as long as the result of that ends up as el on the client, you can mount it with React.render as mentioned above.

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).

React don't mount component until needed but don't unmount afterwards in list of components

Say I am building an instant messaging with app with React (I'm not doing that exactly, but this is easier to explain). I have a sidebar with a list of conversations and, when you click one, it is shown on the right (similar to this). I don't want to mount each conversation component until the user clicks it, but I don't want to unmount it, just hide it, when they click on another conversation. How can I do this cleanly? There will never be more than about 30 chats for any user.
You can store the enabled conversations in an array that you use to show, and when you disable a conversation you can just add a hidden prop to it which you pass to the conversation and make it return null. This will make it not render anything but will not unmount it since you have not removed it from the array that handles the display of conversations.
example at: https://codesandbox.io/s/wispy-forest-59bqj
This is a bit hard to answer since you haven't posted the code.
But, theoretically, the best way to approach this problem is to transfer the data from your sidebar component and load it onto the right component on a per-user basis. You don't have to mount each "conversation component".
You can do this by with the boolean hidden property in your markup. React will render as usual and simply pass it along to the html, the browser will then simply not paint it.
const HideMe = ({ isHidden }) => (
<div hidden={isHidden}>
can you see me?
</div>
)
I made an example for you:
https://codesandbox.io/s/elastic-curie-t4ill?file=/src/App.js
reference: https://www.w3schools.com/tags/att_hidden.asp

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

How render React on server to callback function?

I want render react-app on server with full lifecycle and updates supports.
Like https://github.com/Yomguithereal/react-blessed, but not to terminal, to callback-function.
Example, pseudo-code:
render(<MyComponent />, (tree)=>{
console.log(tree); // new react component-tree
})
Another example, https://github.com/iamdustan/react-hardware
https://github.com/facebook/react/blob/077d660a2727e3d3d6629d3a62693f8509100139/src/renderers/testing/ReactTestRenderer.js#L138
I believe you are looking to implement a "custom renderer" for react. Here's an article that I found that could be helpful:
http://goshakkk.name/react-custom-renderers/

React Component: Foundation Modal (Reveal) won't open

So I've just started learning React and Redux, so I apologize if this is a very noobish question. But I've emptied my Google quote, and can't find anything that helps me.
My problem is: I work on a site with React, Redux, and Foundation 6. One of my React components have a link, that when clicked, should open a Modal with a specific warning for that link. So I've created a component with my modal markup:
ComponentModal.js:
import React, { PropTypes } from 'react';
const Modal = () => (
<div className="reveal" id="exampleModal1" data-reveal>
<h1>Awesome. I Have It.</h1>
</div>
);
export default Modal;
The component with a link renders some stuff, but basically have a
<a data-open="exampleModal1">Click me for a modal</a>
tag in it's render.
And although inspecting the page confirms that the markup for the modal exists, nothing happens when i click the link.
If I move the popup from the component, and into the DOM, the link works.
Some trial and error shows me, that if i manually run $(document).foundation(); in the console when ComponentModal is rendered, the popup works as intended.
So my question is kinda two questions:
1. How do I, in Redux, run $(document).foundation(); when my ComponentModal is done rendering? Maybe I'm wrong, but I don't have the componentDidMount() method available to me, where it might make sense to make that call?
2. Is this a totally wrong way to go about it?
Hope it's not too confusing and not too dumb a question :)
FYI, this question/solution has nothing to do with REDUX!
The problem is that you're trying to use React AND Jquery to make your page do cool things.
You should really choose one or the other.
$(document).foundation() is a Jquery library.
Instead you should use something like React Foundation which removes the jquery dependency and gives you foundation components built with react.
You can do $(document).foundation() in React inside componentDidMount of the component that has the reval modal or better yet You can do this inside componentDidMount of the top most partent in your app.
componentDidMount in React runs once after all the DOM nodes related to that component is mounted. What $(document).foundation() does, if it runs inside componentDidMount, is that it binds event handlers on the elements that have foundation realated attributes like data-dropdown or data-reveal.
componentDidMount() {
$(document).foundation();
}

Resources