Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React component re-render on prop change

import React from 'react';
import { render } from 'react-dom';

const x = [];

const App = props => <div style={styles}>{JSON.stringify(x)}</div>;

render(<App queries={x} />, document.getElementById('root'));

setInterval(x => x.push(Math.random()), 1000, x);
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>React App</title>
</head>

<body>
  <div id="root"></div>
</body>

</html>

Why doesn't the App component rerender when I mutate the object that I passed to it as a prop.

Whenever I close and reopen React Dev Tools, it shows the new props. enter image description here

What is happening here? Please help me understand.

Thanks!

like image 562
mohsinulhaq Avatar asked Apr 13 '26 16:04

mohsinulhaq


2 Answers

The answer in this case is not related to setState. Sure React will automatically re-render when state changes (as long as you didn't do something like use a PureComponent and then mutate the array or object). But you are doing a render from the root and this has nothing to do with react state as your state exists outside of react.

From the react docs on render:

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.

So would need to call render again at the root level for React to reconcile the changes. Also it's better practice to make a new object/array. So in this case you could do x = x.concat(..) and then render again.

let x = [];

const App = props => <div>{props.queries.toString()}</div>;

const renderApp = (queries) => ReactDOM.render(<App queries={queries} />, document.getElementById('root'));

setInterval(() => {
  x = x.concat(Math.random());
  renderApp(x);
}, 1000);

Fiddle: https://jsfiddle.net/ferahl/p7zhs55q/1/

Of course the more usual thing is to use local react state inside react components but it's good to have an understanding of this, and this is how you could implement some global state into react if you weren't using something like redux.

like image 54
Dominic Avatar answered Apr 16 '26 06:04

Dominic


Mutating the data that you pass as props does not trigger a re-render of the component. There is no observer that takes notice of your mutation on that object that could trigger it. In case you have data that changes during the lifetime of a component you need to use state:

import React, {Component} from 'react';
import { render } from 'react-dom';

const x = [];

class App extends Component {
    state = {
        queries: this.props.queries,
    };

    componentDidMount() {
        setInterval(
            () => this.setState(state => ({queries: [...state.queries, Math.random()]}))
        ), 1000);
    }

    render() {
        return <div style={styles}>{JSON.stringify(this.state.queries)}</div>;
    }
}

render(<App queries={x} />, document.getElementById('root'));

This code will initialize the component state with the queries passed via props. When the component did mount it will start the interval which will append a new random number to the state. Calling setState() will trigger a re-render with the new state. Never mutate props.

like image 26
trixn Avatar answered Apr 16 '26 05:04

trixn