Languages
[Edit]
EN

React - change state from props (functional component)

3 points
Created by:
Iona
415

In this article, we would like to show you how to change component state from props in React when we work with functional components.

This article shows two approaches:

  • with useEffect what is the most popular approach in many projects that causes additional re-rendering component cycle,
  • with a custom hook that bases on useRef - which is the optimal solution.

1. useEffect approach example

Below example uses two functional components: MyComponent and App.

States are stored in globalCounter and localCounter. Every button click action inside App component causes passing globalCounter into MyComponent localCounter state via counter props. useState creates state with indicated value only once, so in the below case useState(counter) with new couter value will not cause state change. By using useEffect hook we are able to monitor counter prop value with indicating dependencies via [counter] and update localCounter value with setLocalCounter function always when useEffect detects couter value changes.

// ONLINE-RUNNER:browser;

//Note: Uncomment import lines during working with JSX Compiler.
// import React from 'react';
// import ReactDOM from 'react-dom';

const MyComponent = ({counter}) => {
    const [localCouter, setLocalCouter] = React.useState(counter);
    React.useEffect(() => {
      	setLocalCouter(counter);
    }, [counter]); // <--- when counter value is changed setLocalCouter updates local state
    return (
        <div>
          <span>localCouter={localCouter}</span>
          <button onClick={() => setLocalCouter(localCouter + 1)}>Click me!</button>
        </div>
    );
};

const App = () => {
    const [globalCounter, setGlobalCouter] = React.useState(0);
    return (
        <div>
          <span>globalCounter={globalCounter}</span>
          <button onClick={() => setGlobalCouter(globalCounter + 1)}>Click me!</button>
          <MyComponent counter={globalCounter} />
        </div>
    );
};

const root = document.querySelector('#root');
ReactDOM.render(<App />, root);

2. Optimal solution

Below examples uses useRef and useState to store property and state.

2.1. with useState

// ONLINE-RUNNER:browser;

//Note: Uncomment import lines during working with JSX Compiler.
// import React from 'react';
// import ReactDOM from 'react-dom';

// This approach reduces unnecessary re-rendering.

const usePropState = (prop) => {
    const [current, setCurrent] = React.useState(() => ({prop, state: prop}));
    if (current.prop != prop) {
        current.prop = prop;
        current.state = prop;
    }
    return [
        current.state,
        (state) => {
            setCurrent({prop, state});
        }
    ];
};

const MyComponent = ({ counter }) => {
    const [localCouter, setLocalCouter] = usePropState(counter);
    return (
        <div>
          <span>localCouter={localCouter}</span>
          <button onClick={() => setLocalCouter(localCouter + 1)}>Click me!</button>
        </div>
    );
};

const App = () => {
    const [globalCounter, setGlobalCouter] = React.useState(0);
    return (
        <div>
          <span>globalCounter={globalCounter}</span>
          <button onClick={() => setGlobalCouter(globalCounter + 1)}>Click me!</button>
          <MyComponent counter={globalCounter} />
        </div>
    );
};

const root = document.querySelector('#root');
ReactDOM.render(<App />, root);

2.2. with useRef example

Below approach is a little complicated because uses references to store state. The main idea of the solution is to store state inside reference and force rerendering with counter when the state is changed.

// ONLINE-RUNNER:browser;

//Note: Uncomment import lines during working with JSX Compiler.
// import React from 'react';
// import ReactDOM from 'react-dom';

// This approach reduces unnecessary re-rendering.

const usePropState = (prop) => {
    const [counter, setCounter] = React.useState(0); // to force re-rendering only
    const currentPropRef = React.useRef(prop);       // to help in detection property change only 
    const currentStateRef = React.useRef(prop);      // stores local state
    if (currentPropRef.current != prop) {            // property change detection
        currentPropRef.current = prop;
        currentStateRef.current = prop;
    }
    return [
        currentStateRef.current,
        (newState) => {
            currentStateRef.current = newState;
            setCounter(counter => counter + 1);
        }
    ];
};

const MyComponent = ({ counter }) => {
    const [localCouter, setLocalCouter] = usePropState(counter);
    return (
        <div>
          <span>localCouter={localCouter}</span>
          <button onClick={() => setLocalCouter(localCouter + 1)}>Click me!</button>
        </div>
    );
};

const App = () => {
    const [globalCounter, setGlobalCouter] = React.useState(0);
    return (
        <div>
          <span>globalCounter={globalCounter}</span>
          <button onClick={() => setGlobalCouter(globalCounter + 1)}>Click me!</button>
          <MyComponent counter={globalCounter} />
        </div>
    );
};

const root = document.querySelector('#root');
ReactDOM.render(<App />, root);

Alternative titles

  1. React - change state on props change (functional component)
Donate to Dirask
Our content is created by volunteers - like Wikipedia. If you think, the things we do are good, donate us. Thanks!
Join to our subscribers to be up to date with content, news and offers.

ReactJS

React - change state from props (functional component)
Native Advertising
🚀
Get your tech brand or product in front of software developers.
For more information Contact us
Dirask - we help you to
solve coding problems.
Ask question.

❤️💻 🙂

Join