Kawd
Kawd

Reputation: 4450

functional component doesn't re-render on props change

In the code below, whenever I get new props from the parent, the new props are logged correctly on the console, but the rendered HTML is never updated after the initial render:

export default function(props) {
  const [state, setState] = useState(props)
  
  // initially, props.something is defined
  // every time props changes (from the parent) props.something is redefined as expected and logged here
  console.log(props.something)
  
  // initially, props.something is rendered correctly
  // every time props.something changes (from the parent) the HTML never updates
  return (
    {state.something && <div>{state.something}</div>}
  )
} 

I already tried using useEffect() even though I don't see the point, but it it didn't fix anything.

Upvotes: 5

Views: 9382

Answers (3)

Lin Du
Lin Du

Reputation: 102257

You might not need an effect to sync state from props, See Resetting all state when a prop changes. You can pass a key prop to the component so that whenever the key changes, React will recreate the DOM and reset the state of the component and all of its children

import { useState } from 'react';

const MyComponent = (props) => {
  const [state, setState] = useState(props);
  console.log(props.something);
  return state.something ? <div>{state.something}</div> : null;
};

function App() {
  const [count, setCount] = useState(0);
  return (
    <>
      <button onClick={() => setCount((count) => count + 1)}>increase</button>
      <MyComponent something={count} key={count} />
    </>
  );
}

export default App;

stackblitz

Upvotes: 1

JBaczuk
JBaczuk

Reputation: 14609

State will not update just because props change, this is why you need useEffect.

export default function(props) {
  const [state, setState] = useState(props)

  useEffect(() => {
    setState(props.something)
  }, [props.something])
  
  // initially, props.something is defined
  // every time props changes (from the parent) props.something is redefined as expected and logged here
  console.log(props.something)
  
  // initially, props.something is rendered correctly
  // every time props.something changes (from the parent) the HTML never updates
  return (<div>{state.something}</div>)
} 

adding props.something to the array as the second argument to useEffect tells it to watch for changes to props.something and run the effect when a change was detected.

Update: In this specific example, there is no reason to copy props to state, just use the prop directly.

Upvotes: 9

Alexander Sakhatskii
Alexander Sakhatskii

Reputation: 703

In your example you copy props to state only once, when initial values set.

It's almost never a good idea to copy props to component state though. You can read about it react docs

Upvotes: 1

Related Questions