https://codesandbox.io/s/cocky-silence-486sh?file=/src/App.js
In the above example, we see that calling the ChildWrapper as ChildWrapper() vs <ChildWrapper/> causes some differences.
The function method behaves as intended, so when I increment the counter, the reference stays the same, however using the component call, it actually remounts.
I was wondering if my intuition is correct, that the references are changing, and more important why are they changing. And to add on to that, which should be the preferred method for rendering functions that returns jsx, <Component/> or { Component() }.
When you do <ChildWrapper/> it is translated to React.createElement(ChildWrapper, {}, null) which means you ask react to create an element for you.
When you do ChildWrapper() you are just calling a function, react does not know about this and cannot know about it, so you won't have any of react's features (hooks).
With your example, with logging the two results in the console you will see this, and you can notice that the difference is noticeable:
When calling the function, it will return a <div>, here, jsx will transpiles it to an object with type div.
When calling it via jsx from the start, it will return an object with type ChildWrapper.
PS: you are creating the ChildWrapper inside a component (during render) So it will have a new value each time your Parent component renders, and react after rendering and going into reconcialiation, it will remove the whole previous tree and create a new one, because the type changed.
Let's sum up all what I've wrote:
The child "behaving correctly for you" is the function call, because you basically call it and it returns a div, react after render and during reconciliation, finds a div and then just updates it if there is a change. So the mount useEffect(() => ..., []) will not be executed.
Why the child created with jsx isn't behaving correclty ? because you are dynamically creating its type, so at each render, it will create a new ChildWrapper Type, and react during reconciliation will remove it entirely because its type changed, and thus, the mount useEffect(() => ..., []) will be executed each time, because every time we mount a new element.
Read more about reconciliation in this link
From the official documentation :
Each JSX element is just syntactic sugar for calling
React.createElement(component, props, ...children). So, anything you
can do with JSX can also be done with just plain JavaScript.
Internally, the code generated looks like this: React.createElement(Component, { props }, children),
The createElement function will then register and render the component you gave to it, bind it with the shadow DOM and update it whenever it is necessary. It will also pass its props and children arguments.
But if you call your component directly, none of that happens, your component will not be correctly rendered and updated by react because it lacks the core features given by createElement.
I've just started learning React and in the ReactDOM.render there is document.getElementById('someid'), what does it do?
It's the container to which the contents of the first parameter will be rendered to.
Check out public/index.html in your project if you use create-react-app. You should be able to find the <div> with an ID of root (the default value for create-react-app). You can change the ID of that div, but you will have to change the ID in the getElementById call in your index.js.
Here's what the documentation says about it: https://reactjs.org/docs/react-dom.html#render
ReactDOM.render(element, container[, callback])
Render a React element into the DOM in the supplied container and
return a reference to the component (or returns null for stateless
components).
If the React element was previously rendered into container, this will
perform an update on it and only mutate the DOM as necessary to
reflect the latest React element.
is it true, the purpose of Ref is replacing document.getElementById??
Once i apply react, i should not use document.getElementById to access DOM to get data?
i found some article said that we can apply the this.refs to access the DOM
<input ref="test" value="option" id="option4"/>
console.log(this.refs.test);
But it can only run within the method within the component,
what if i want show the input value in console (developer Tools)?
It is true in a way, because react uses its virtual dom and diffing algorithm to watch changes and reflect in dom. If you use direct api to access dom. react could not access it in its virtual dom.
Thats why they have an unique id or keys just like in DOM to manipulate elements (components) as node.
If you see in confirm-alert components used in npm packages, they will create an element and render it as an element by using ReactDOM. As soon the toaster is finished it is not removed directly from the DOM.
First it is made to be find from the reactVirtualDom by using api findDomNode at https://reactjs.org/docs/react-dom.html#finddomnode
then it is unmounted using unmountComponentAtNode.
https://reactjs.org/docs/react-dom.html#unmountcomponentatnode
For example: https://github.com/GA-MO/react-confirm-alert/blob/master/src/index.js
So, refs are used to overcome direct DOM manipulation and changes that affect or effects the react rendering process.
Consider the following scenario:
I have a piece of (safe) HTML that I import in a js module and add to a React component using the dangerouslySetInnerHtml prop.
I then use the escape hatch that refs provide to access the mounted React component.
let foo = this.refs.foo;
And add an event listener to a DOM element inside that mounted component
foo.querySelector('a').addEventListener('click', callback, true);
Question Will React remove this event listener automatically when the component is unmounted, or do I need to do this manually in componentWillUnmount? I can't imagine why React wouldn't remove it along with the DOM node it was added to, but I couldn't find any reference to support or contradict my intuition.
What do you think?
Modern browsers will collect event handlers of removed DOM elements.
But if you hold a reference of that DOM element somewhere, the event handlers can't be collected by a browser and cause memory leak.
So the safest way is to remove all the event handlers in your componentWillUnmount.
If I render a component into a domNode and then again render another component into the same domNode my understanding is that this is a replace operation rather than an append. The first component will be removed from the dom and from the React Tree in the Virtual representation of the DOM. Therefore I don't need to specifically call ReactDOM.unmountComponentAtNode to clean up the first component.
Is this correct?
That is correct. According to the ReactDOM docs, on ReactDOM.render():
In the future, it may be possible to insert a component to an existing DOM node without overwriting the existing children.
This means that it is not even currently possible to append using ReactDOM.render() - components always get destroyed and replaced.
Generally it is better to avoid the ReactDOM module unless completely necessary. For most React apps, you'll find it is only used to render just the top level wrapper component to the DOM.