I am developing a component where i have to change state on scrollview scroll, means on onScroll function call. I have some child components in it as well ... when I do setState parent component re-renders and also re-renders to its child components.
There is a child component having banner and description which I donot update on this screen but it also re-renders and create flickering effect which looks weird.
const [state, setState] = useState('');
setState('MOVING');
I also convert that child component from functional component to PureComponent but it still re-rendering.
There is no state update for this child component but it re-render as its parent re-render.
Please help to stop re-rendering of this child component as there is not state change in it.
Any solution to make it fix.
thanks.
Your question is related to this issue. How to stop re render child component when any state changed in react js?
To stop re-render on child components you can use React memo, or useMemo if you use react hooks.
I have same issue about rerendering on child when I used React.context with lot of unneeded data passing to child. So, u can limit what should child component refer to rerender when props change with useMemo
import React, { Component, useState, useMemo } from "react";
import { render } from "react-dom";
import Child from "./components/child.js";
import "./style.css";
function App() {
const [number, setNumber] = useState(0);
function handleOnClick() {
setNumber(number + 1);
}
//memo child not rendering when state update, only render child props update.
const memoChild = useMemo(() => <Child />, []);
// useMemo's second arguments is state variable name. example [number]. if 'number' gets update, child component rerender will be happen.
// const memoChild = useMemo(() => <Child />, [number]);
return (
<div>
<h1>Use Memo</h1>
<div className="box">
<h2>Parent Component</h2>
<h4>Number : {number}</h4>
<button onClick={() => handleOnClick()}> Increment </button>
</div>
<div className="box">
<h2>Normal child component </h2>
<Child /> {/*Every state update it gets rerendered */}
</div>
<div className="box">
<h2>Memo child Component </h2>
{memoChild}
</div>
</div>
);
}
render(<App />, document.getElementById("root"));
for more references
Re-rendering component tree is something react manages well. In terms of performance, if you are looking for a way to manage not necessary re-renders I suggest you have a look at a few useful hooks, useMemo, useCallback, and a higher order component React.memo.
With these three hooks, you are able to prevent child components from re-rendering, if parent is updated.
const Parent = () => {
const [childAState, setChildAState] = useState();
useEffect(() => {
setChildAState('Child A Updated');
}, []);
return (
<>
<ChildA childAState={childAState}/>
<ChildB />
</>
);
};
const ChildA = () => React.memo((props) => {
return <h1>Child A</h1>
});
const ChildB = () => React.memo((props) => {
return <h1>Child B</h1>
});
In the above example, ChildB wont re-render if a state in Parent does change and leads to an update in ChildA.
Further reading: React.memo
Related
In Father component I render Child component that is a form with states inside. When I render Father i don't want to mount Child component and reset it's states. It is possible?
I tried rendering Child component using useMemo hook, but it mounts the component everytime the hook returns it.
const Father = () => {
const [formData, setFormData] = useState(null);
const renderForm = useMemo(() => {
return (
<Child
setDefaultFormData={(value) => setFormData(value)}
>
</Child>
);
}, [formData]);
return (
<>
<div>{renderForm}</div>
</>
);
};
export default Father;
Any help out there? Thanks.
I'm not quite sure why you added formData to the useMemo dependency list.
You are updating formData based on the previous state, and formData is not needed in the dependency list.
Try this:
const renderForm = useMemo(() => {
return (
<Child
setDefaultFormData={(value) => setFormData(value)}
>
</Child>
);
}, []);
useMemo works as expected in this case, it only updates when some dependencies in the dependency list have been updated.
This part of code setDefaultFormData={(value) => setFormData(value)} leads to the creation of a new function every time the parent renders which causes the Child component to re-render because prevProps.setDefaultFormData != nextProps.setDefaultFormData, beside that React by default re-renders all children when parent component renders, so you have to wrap your child component with React.memo() and pass setFormData directly setDefaultFormData={setFormData} and use it normally
I want same value in Home function from Component and Home function should not rerender when Component useState is updating.
import { useState, useEffect } from "react";
function Component() {
const [count, setCount] = useState(0)
useEffect(() => {
console.log("rerender")
})
useEffect(() => {
let interval = setInterval(() => {
setCount(Math.floor(Math.random() * 1000))
}, 1000)
return () => clearInterval(interval)
}, [])
return count
}
function OtherStuff() {
console.log("OtherStuff")
return (<h1>Should Not Rerender OtherStuff</h1>)
}
function MoreStuff() {
console.log("MoreStuff")
return (<h1>Should Not Rerender MoreStuff</h1>)
}
export default function Home() {
return (
<>
<h1>Hello</h1>
<h1>
<Component />
</h1>
<OtherStuff />
<MoreStuff />
<h1>
<Component />
</h1>
</>
);
}
I have called Component function two times, I want same value should render to both from Component.
and when ever Component {count} is update by using setCount, Main function should not rerender. at this time, there is no rerender for Component in Main function which is OK.
this is the simple problem.
Thanks.
Each instance of a component has its own state. Meaning their states are not shared. If you wanna share the state between them, one way would be to lift the state up.
If you do not want the Home to rerender, you cannot move the state to Home. So you probably need another component which holds the state. Because any component which has a react useState hook, will be rerendered when the state is updated.
You can use react context to do so. Wrap your instances of Component inside a context provider which holds the count state and provides count and setCount.
First you need to create a context:
const CountContext = createContext();
Then create a component which provides the context and holds the state:
const CountProvider = (props) => {
// `useCounter` uses `useState` inside.
const [count, setCount] = useCounter();
return (
<CountContext.Provider value={{ count, setCount }}>
{props.children}
</CountContext.Provider>
);
};
(OP provided a codesandbox which uses useCounter custom hook. It stores a number to count state and updates it to a random number every 1000ms.)
Then wrap it around your components:
function Parent() {
return (
<div>
<CountProvider>
<Counter />
<Counter />
</CountProvider>
</div>
);
}
codesandbox
Note that:
If you render another component inside CountProvider using children prop, it will NOT rerender every time count state updates, unless it uses the context.
But if you render a component inside CountProvider and render it in the function, it WILL rerender, unless you use memo.
I'm trying to understand the rendering in ReactJS. I'm following this tutorial from YouTube, but I want a better grasp on the subject. The video explains that if you pass down the child component
<Child/>
Then it will trigger a render of the parent and the child.
However if you pass down
{props.children}
Then it will only update the parent, if there are no changes to the children. But what if I have a series of different children? What if I have 20 children or 100? And I want to pass a prop to a specific child? Say I want to pass down a prop to the 50th child (or any other). Then how would I go about in doing this?
Say that I want to pass down these constants, would the children only re-render if they receive a prop or would they all re-render?
const [childA, setChildA] = useState("In Child A")
const [childB, setChildB] = useState("In Child B")
I tried using the code from How to pass props to {this.props.children}
{React.Children.map(props.children, function(child){
if(React.isValidElement(child)){
let clone = React.cloneElement(child, {...props})
return clone
}
But I'm not sure what I'm doing, I'm think I'm in the right path, but I'm not sure how to get what I'm looking for.
Parent component
import React, { useState } from 'react';
function ParentCount(props) {
const [count, setCount] = useState(0)
console.log("Parent render")
return (
<div>
<button onClick={()=>setCount(v=>v+1)}>Parent Increase +1</button>
Parent count is {count}
Children count
{React.Children.map(props.children, function(child){
if(React.isValidElement(child)){
let clone = React.cloneElement(child, {...props})
return clone
}
})}
</div>
);
}
export default ParentCount;
App component
function App() {
return (
<div className="App">
<ParentCount>
<ChildCount></ChildCount>
<ChildCount></ChildCount>
</ParentCount>
</div>
);
}
export default App;
Child component
import React, {useState} from 'react';
function ChildCount(props) {
const [count, setCount] = useState(0)
console.log("Child render")
return (
<div>
<button onClick={()=>setCount(v=>v+1)}>Child Increase +1</button>
<div>Child count is {count}</div>
</div>
);
}
export default ChildCount;
the meaning of the first lines you wrote is this:
if you pass a prop to a child component, react will only update that component for you. ex:
<ChildComponent prop1 = 'hi'>
if you add a whole new child component to your Component, react will update your parent too:
function ParentComponent () {
const [update, setUpdate] = useState(0);
let updateComponent = null;
if (update === 1) {
updateComponent = <UpdateComponent></UpdateComponent>;
}
return (
<div>
{ updateComponent }
</div>
)
}
sorry for bad example
I have A parent component with a child modal component. the parent component has a blank state variable passed down to child. the parent component also has a div that needs editorState initialized on render to work properly. My child component has a button that sets stateForDiv with some data to render in parent components div. I need parent component to setEditorState when child updates stateForDiv. Naturally I tried to use useEffect with stateForDiv as dependency. Well when the useEffect runs it creates and infinite loop when I run setEditorState. How can I set EditorState every time the stateForDiv changes without creating an infinite loop?
import React, {useState, useEffect} from 'react';
import {convertFromRaw, EditorState } from 'draft-js';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
const [ editorState, setEditorState ] = useState(() => { return EditorState.createEmpty()}) // this must be initialized once on render
const [ stateForDiv, setStateForDiv ] = useState() // this state is passed down to child component, when the child component updates this state, we need to setEditorState.. this is my problem, infinite loop in useEffect when using stateForDiv as dependency
useEffect(() => {
if(stateForDiv) {
setEditorState(EditorState.createWithContent(
convertFromRaw(stateForDiv)));
} else {
console.log("false")
}
}, [stateForDiv])
return (
<div currentContent={editorState} onChange={setEditorState} >
</div>
<div>
<Modal>
<ChildComponent setStateForDiv={setStateForDiv}
</Modal>
</div>
Child component that is setting state for stateForDiv
const ChildComponent = ({setStateForDiv}) => {
return (
<div>
<button onClick={() => {setStateForDiv("<p>hi there</p>")} } ></button>
</div>
)
}
First point, const [ stateForDiv, setStateForDiv ] = useState() this statement is not required. Beacause you just want <ChildComponent /> component which onClick event to control <div currentContent={editorState} > component display. You can <ChildComponent onClick={setEditorState(EditorState.createWithContent(convertFromRaw("<p>hi there</p>")));}/>.
In addition, why your useEffect infinite loop.As your useEffect dependence is wrong.So you should take care how to use dependence.
I am learning latest react features. As per docks memo works like shouldComponentUpdate or PureComponent in functional component but how do I use this memo concept in functional component.
Say I have below component using class
import React, { Component } from 'react';
class Test extends Component {
shouldComponentUpdate(nextProps, nextState) {
return this.props.text != nextProps.text;
}
render(){
const { text } = this.props;
return(
<div>
<h1>{text}</h1>
</div>
)
}
}
Functional component
function Test = props => {
const { text } = props;
return(
<div>
<h1>{text}</h1>
</div>
)
}
How can I write class component using memo in functional component
Memo works as a higher order component, and you can simply just wrap your functional component export with it. Every time your application updates, memo will automatically perform a shallow comparison of props to determine if they've changed, and if the component needs to re-render.
export default React.memo(Test);
React.memo() is a HOC that takes a functional component and returns a component that behaves the same as a PureComponent.
const MyComponent = React.memo(function MyComponent(props) {
/* only rerenders if props change */
});
Update:
React.memo also accepts a compare function as second argument. By using this function, we can compare props not in a shallow way but whichever way we want to. This gives more control over preventing update of component.
Use this function when your props contain complex Objects and you want to compare fields of these Objects while determining if your component should update.
E.g.
const MyComponent = React.memo(function MyComponent(props) {
/* only rerenders if props change */
}, (props1, props2) => {
prop1.my_property_to_check === prop2.my_property_to_check
});