React 16.13.1 - child component does not re-render when props change
It looks like the same expression
object is being passed in all the time.
React checks the props
that a component receives for changes when deciding to render. It finds that none of the props
items have changed, they are all the same objects as before, and concludes that the child component does not need to be rerendered. It will not do a deep inspection of all properties of each prop.
This also explains why a rerender can be forced by making a copy of the expression object. The copy is always a new object, thus causing a rerender, regardless if any of its content have changed or not.
You could avoid this situation as you do already, by making a copy, or by dissecting the expression
object into its properties and then feeding each of those as separate props
into the child.
As a final note, a copy can also be made by passing it in as expression={{...expression}}
.
React child component not updating when props change
You mutate your state object in your handleChange
function. The component doesn't rerender because searchState
is still the same object reference from the previous render cycle.
let handleChange = (event) => {
searchState['results'] = searchProducts(event.target.value); // mutation!
searchState['query'] = event.target.value; // mutation!
setSearchState(searchState); // safe reference back into state
};
You shouldn't mutate state object directly. Use a functional state update and shallow copy existing state into a new state object reference. Then update the properties you want to update.
let handleChange = (event) => {
const { value } = event.target;
setSearchState(searchState => ({
...searchState,
results: searchProducts(value),
query: value,
}));
};
React not re-rendering child component after updating state var passed as prop
Found the answer! The resetPaint value in the parent was getting re-set before the cells had had time to finish rendering. Moving it to a useEffect like so solved the problem.
useEffect(() => {
resetPaint && setResetPaint(false);
}, [resetPaint]);
I've updated the codesandbox to reflect this.
Component not updating when I change the props that I pass to it in React
A component only updates once either its state
changes or its props
change. A state
is a variable or set of variables which is remembered when the component re-renders. All other variables will go back to their default value as soon as the component re-renders. You can see it as the component's memory.
So in your case changing your text
variable won't update your parent
's state, and thus won't re-render the component, which in return won't re-render and update the child's component.
If you want your parent component to update it's state (and update the child
's props) you need to declare your text variable like this:
const [text, setText] = React.useState("This is the original text");
Text is your variable, it is now included within your component's state and will be remembered when the component re-renders. You can give this any name you want.
setText is a function which updates your text
variable and also re-renders your component and it's children. You can give this any name you want.
"This is the original text" is your initial state, the initial value for your text
variable.
To update your state you can do something like this:
setText("This is the new text");
So in your case it will look something like this:
function MainPage(){
const [text, setText] = React.useState("This is the original text");
React.useEffect(() => {
const timeout = setTimeout(function(){
setText("This is the new text")
}, 3000);
return clearTimeout(timeout)
}, []);
return(<DisplayText text={text} />);
}
useEffect is necessary to be able to define your setTimeout as soon as the component mounts. It can be use to execute some code as soon as a certain variable (defined between the []
brackets) updates. For example: If you wrote it like this:
React.useEffect(() => {
// execute some code
}, [text])
It would execute some code as soon as your text
variables changes. Leave the []
brackets empty to only trigger useEffect
when the component mounts and unmounts.
Within the useEffect
hook you declare your setTimeout, this sets your timer as soon as the component mounts in this case.
The return
method within your useEffect
clears your timeout again as soon as the component unmounts. This will prevent your timer from running indefinitely after your component unmounts.
React doesn't update child when props change?
Because you don't update state in StatefulEditor when props change. You need to add useEffect
to update.
const StatefulEditor = (props) => {
const [name, setName] = useState(props.item.name);
const [description, setDescription] = useState(props.item.description);
useEffect(() => {
setName(props.item.name);
setDescription(props.item.description);
}, [props.item]);
...
https://codesandbox.io/s/dervied-state-from-props-problem-forked-uiidu?file=/src/components/EditableList.jsx
Why React component doesn't re-render (change styles) when props changed?
This is a classic case of copying props into local state -- which you usually do not want to do as it introduces a surface area for bugs, including the one you are seeing. If something is available as a prop -- what is the purpose of copying it into local state? You should instead use callbacks to alter wherever the state of that prop lives in the ancestors. Copying means you now have to manage keeping the local state and prop in sync -- which is why usually copying in the first place is an antipattern.
The reason the state doesn't update when isSelected
changes is because the parameter to useState
is only its initial value. By design, even when a rerender occurs due to the prop changing, the state item wont update. Copying it into local state means its up to you to keep them in sync (common cause of bugs).
Two choices:
Option A
Don't copy props into state, so you don't even need to deal with making sure the props and internal state are in sync. Use isSelected
directly and remove the state item. To set the selected state, you will need to pass down into the component from the parent a callback over props -- which accepts the changed value and changes the state in that parent component. This gets rid of the pointless barrier in between the props and the actual thing you are rendering.
Option B
If you must keep a copy of the state around for some reason, make sure you update the state when the props change with an additional effect.
type TagItemProps = {
tag: Tag;
isSelected: boolean;
onSelect: (tag: Tag) => boolean;
onDeselect: (tag: Tag) => void;
};
const TagItem = ({ tag, isSelected = false, onSelect, onDeselect }: TagItemProps) => {
const [selected, setSelected] = useState(isSelected);
useEffect(() => {
setSelected(isSelected )
}, [isSelected ])
console.log("isSelected: ", isSelected);
console.log("selected: ", selected);
const handleSelect = useCallback(() => {
if (!onSelect(tag)) return;
setSelected(true);
}, [onSelect, tag]);
const handleDeselect = useCallback(() => {
onDeselect(tag);
setSelected(false);
}, [onDeselect, tag]);
return (
<TouchableOpacity
style={[styles.container, selected ? styles.selected : null]}
onPress={selected ? handleDeselect : handleSelect}
>
<Text style={[styles.text, selected ? { color: '#fff' } : null]}>
{capitalizeFirstLetter(tag.name)}
</Text>
</TouchableOpacity>
);
};
export default TagItem;
const styles = StyleSheet.create({
container: {
flex: 0,
backgroundColor: '#fff',
borderRadius: 20,
paddingHorizontal: 10,
paddingVertical: 12,
margin: 5,
},
selected: {
backgroundColor: 'green',
},
text: {
textAlign: 'center',
fontWeight: 'bold',
},
});
Related Topics
Password Encryption at Client Side
Testing Whether a Value Is Odd or Even
Converting Any String into Camel Case
Window.Open and Pass Parameters by Post Method
What Happens When Using This.Setstate Multiple Times in React Component
How to Convert an Iso Date to the Date Format Yyyy-Mm-Dd
Prevent Safari Loading from Cache When Back Button Is Clicked
How to Use Jquery in Chrome Extension
How to Stop Event Bubbling on Checkbox Click
Return Positions of a Regex Match() in JavaScript
Why Use Jquery On() Instead of Click()
Has Facebook Sharer.PHP Changed to No Longer Accept Detailed Parameters
How to Assign JavaScript Variable Value to PHP Variable
How to Display Pie Chart Data Values of Each Slice in Chart.Js
Only on Firefox "Loading Failed for the <Script> with Source"
How to Send Variables from One File to Another in JavaScript