2
votes

I have tried this pattern.

ParentComponent
...
render(
return <ChildComponent newProps="newPropsValue />)

ChildComponent
...
ComponentWillReceiveProps{
this.setState({"propsKey": "newPropsValue"})
}

As far as I understand the initial component rendering is triggered by the props change, and as setState is asynchronous (for some reason), the rendering with the new state update is not done on the first pass.

However what I don't understand is why when it finally decides to update the state, it doesn't rerender the component. I thought state changes that are caused by setState always trigger a rerender.

So in the end I have a component that uselessly rerenders before the state is actually changed, and then does nothing when/if(?) the state is updated. I don't understand this behaviour at all.

2

2 Answers

0
votes

setState will trigger componentUdpate -> componentWillUpdate -> render. props change will trigger componentWillReceiveProps before this chain. You can have a look here at this image about React lifecycle. You can see the different how React behave on props and state.

So:

However what I don't understand is why when it finally decides to update the state, it doesn't re-render the component.

Updating state by setState will trigger the render function (re-render). And props also trigger render as well.

Following your code:

  1. componentWillReceiveProps:
    • this.props.newProps="newPropsValue"
    • this.state.propsKey="newPropsValue"
  2. render: as above, nothing change.
  3. If any event of childComponent setting propsKey by setState (onClick, onChange ...). Assuming setState({propsKey: "anotherValue"}). Then render will be triggered again with this.state.propsKey="anotherValue and this.props.newProps="newPropsValue"

Now let's update your childComponent's props within parentComponent, assuming newProps="latestPropsValue":

  1. Before componentWillReceiveProps:
    • this.props.newProps="latestPropsValue"
    • this.state.propsKey="anotherValue"
  2. After componentWillReceiveProps:
    • this.props.newProps="latestPropsValue"
    • this.state.propsKey="latestPropsValue"

How do I force a child component to rerender when given new props values?

If your render is using state then setState inside render. And if you are using props inside render, it also being updated accordingly

0
votes

I have found a nice solution using key attribute. If we changed key property of a child component or some portion of React Component, it will re-render entirely. It will use when you need to re-render some portion of React Component or re-render a child component depending on props or state. Here is a example. I will re-render the full component.

import React, { useState, useEffect } from "react";
import { PrEditInput } from "./shared";

const BucketInput = ({ bucketPrice = [], handleBucketsUpdate, mood }) => {
  const data = Array.isArray(bucketPrice) ? bucketPrice : [];
  const [state, setState] = useState(Date.now());
  useEffect(() => {
    setState(Date.now());
  }, [mood, bucketPrice]);
  return (
    <span key={state}>
      {data.map((item) => (
        <PrEditInput
          key={item.id}
          label={item?.bucket?.name}
          name={item.bucketId}
          defaultValue={item.price}
          onChange={handleBucketsUpdate}
          mood={mood}
        />
      ))}
    </span>
  );
};

export default BucketInput;