Trigger child re-rendering in React.js

JavascriptReactjs

Javascript Problem Overview


The Parent (MyList in my example) component renders an array thru a Child (MyComponent) component. Parent decides to change properties in the array, what is React way of triggering child re-rendering?

All I came up with is this.setState({}); in Parent after tweaking the data. Is this a hack or a React way of triggering an update?

JS Fiddle: https://jsfiddle.net/69z2wepo/7601/

var items = [
  {id: 1, highlighted: false, text: "item1"},
  {id: 2, highlighted: true, text: "item2"},
  {id: 3, highlighted: false, text: "item3"},
];

var MyComponent = React.createClass({
  render: function() {
    return <div className={this.props.highlighted ? 'light-it-up' : ''}>{this.props.text}</div>;
  }
});

var MyList = React.createClass({
  toggleHighlight: function() {
    this.props.items.forEach(function(v){
      v.highlighted = !v.highlighted;
    });
        
    // Children must re-render
    // IS THIS CORRECT?
    this.setState({});
  },
    
  render: function() {
    return <div>
      <button onClick={this.toggleHighlight}>Toggle highlight</button>
      {this.props.items.map(function(item) {
          return <MyComponent key={item.id} text={item.text} highlighted={item.highlighted}/>;
      })}
    </div>;
  }
});
 
React.render(<MyList items={items}/>, document.getElementById('container'));

Javascript Solutions


Solution 1 - Javascript

The problem here is that you're storing state in this.props instead of this.state. Since this component is mutating items, items is state and should be stored in this.state. (Here's a good article on props vs. state.) This solves your rendering problem, because when you update items you'll call setState, which will automatically trigger a re-render.

Here's what your component would look like using state instead of props:

var MyList = React.createClass({
    getInitialState: function() {
        return { items: this.props.initialItems };
    },
    
    toggleHighlight: function() {
        var newItems = this.state.items.map(function (item) {
            item.highlighted = !item.highlighted;
            return item;
        });
        
        this.setState({ items: newItems });
    },
    
    render: function() {
        return (
            <div>
                <button onClick={this.toggleHighlight}>Toggle highlight</button>
                { this.state.items.map(function(item) {
                    return <MyComponent key={item.id} text={item.text} 
                             highlighted={item.highlighted}/>;
                }) }
            </div>
        );    
    }
});

React.render( <MyList initialItems={initialItems}/>,
              document.getElementById('container') );

Note that I renamed the items prop to initialItems, because it makes it clear that MyList will mutate it. This is recommended by the documentation.

You can see the updated fiddle here: https://jsfiddle.net/kxrf5329/

Solution 2 - Javascript

I have found a nice solution using key attribute for re-render with React Hook. 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 of re-render a child component. 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;

Solution 3 - Javascript

An easy option to re-render a child is to update a unique key attribute every time you need a re-render.

<ChildComponent key={this.state.updatedKey}/>

Solution 4 - Javascript

You should trigger a re-rendering by calling setState() and giving the new props you want to propagate down. If you really want to force an update you can also call forceUpdate().

If you look at the examples on this page, you can see that setState is the method used to update and trigger a re-rendering. The documentation is also stating (ahaha!) that clearly.

In your case I would call forceUpdate.

EDIT: As Jordan mentioned in the comment, it would be better to store items as part of your state. That way you wouldn't have to call forceUpdate but you would really update the state of your component, thus a regular setState with the updated values would work better.

Solution 5 - Javascript

You can set a numeric key on the child component and trigger a key change once an action is performed. e.g

state = {
        childKey: 7,
};



<ChildComponent key={this.state.childKey}/>


actionToTriggerReload = () => {
const newKey = this.state.childKey * 89; // this will make sure the key are never the same
this.setState({childKey: newKey})
   }

This will surely re-render the ChildComponent

Solution 6 - Javascript

Set a numeric default 'key' in the child component and to re-render just change key value.

this.state = {
        updatedKey: 1,
};    
triggerReload = () => {
let newKey = Math.floor(Math.random() * 100); // make sure the key are never the same
this.setState({updatedKey: newKey})
   }
<childComponent key={this.state.updatedKey} handlerProp = {this.onClickItemEvent} />

This worked for me to re-render the ChildComponent in reactjs class base

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDjamView Question on Stackoverflow
Solution 1 - JavascriptJordan RunningView Answer on Stackoverflow
Solution 2 - JavascriptTofazzal haqueView Answer on Stackoverflow
Solution 3 - JavascriptAslam ShekhView Answer on Stackoverflow
Solution 4 - JavascriptJeremy DView Answer on Stackoverflow
Solution 5 - JavascriptLekensView Answer on Stackoverflow
Solution 6 - JavascriptSubhomoy halderView Answer on Stackoverflow