21

I'm using React hooks for app state, I wondered about how to initialize the function component state using props? The useState hook doc says something definitive like,

const [count, setCount] = useState(0);

I want to initialize that 0 value by the value of props being passed to the component. The Older as,

import React from 'react';

export default class Sym extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      sym : [0,3,2,8,5,4,1,6],
      active: this.props.activeSym
    }
    this.setActive = this.setActive.bind(this);
  }

  setActive(itemIndex) {
    this.setState({
      active: itemIndex
    });
  }

  render() {
    return (
      <div>
        <h1>
          {this.state.sym[this.state.active]}
        </h1>
      </div>
    );
  }
}

works fine. Where the parent component passes activeSym prop and Sym component initializes the state with it using this.props.activeSym in constructor. Is there any workaround to achieve same in function component?

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
Kiran Maniya
  • 8,453
  • 9
  • 58
  • 81

6 Answers6

33

First you can define it from props (if the prop exist):

const [count, setCount] = useState(activeSym);

And then you can update this value, when prop doesn't have a value immediately (when component rendered):

useEffect(() => {
  if (activeSym) {
    setCount(activeSym);
  }
}, [activeSym])
demkovych
  • 7,827
  • 3
  • 19
  • 25
  • 1
    why would not have a value inmediately? – oskrgg Dec 16 '21 at 16:43
  • directly assign props as default state will lead to multiple sources of truth. – ilumin Sep 08 '22 at 09:43
  • @ilumin re "multiple truths". Could you elaborate, please? In my experience, assigning props as default state sometimes works and sometimes doesn't. Where it doesn't, useEffect as described above seems to fix things. I'd really like to get a better understanding of what's going on here. When I can't initialise a state with props, it's in a component that has been previously rendered and which already seems to have state values. – MartinJ Sep 28 '22 at 14:21
12

Yes, this can be possible with functional component too! You just need to add useEffect to listen to prop change for initializing state with prop value

export const newComponent = (props) => {
  const { path, value, info, update } = props;
  const [val, setVal] = useState(value);

  useEffect(() => {
    setVal(value);
  }, [value]);

  return <div>{val}</div>;
};

Attching sandbox link

https://codesandbox.io/s/confident-agnesi-ohkq7?file=/src/MakeComponent.js

Riddhi Patel
  • 221
  • 3
  • 8
1

Yes you can first define state using props:

const [name, setName] = useState(props.obj?.name);

And then you can if the state is still undefined means props doesn't have a value, then:

useEffect(() => {
  if (JSON.stringify(props.obj) !== "{}") {
    setName(props.obj?.name);
  }
}, [props.obj])
0

Just as follows :

const MyFunctionalComponent = ({myProp}) => {
  const [count, setCount] = useState(myProp)

  return (
     /* ... */
  )
}
0
export const newComponent = (props) => {
  const { path, value, info, update } = props;
  const [val, setVal] = useState(value);

  useEffect(() => {
    setVal(value);
  }, [value]);

  return <div>{val}</div>;
};

this code by riddhi can be

export const newComponent = (props) => {
  const { path, value, info, update } = props;

  return <div>{value}</div>;
};

since the value prop changes on every update from parent there is no need to update it using useeffect especially since the dependency array only contains value

Please do not store props in state but instead use them directly as it may lead to hard to find bugs later on when state is not updated properly

-2

There are two ways you can change the state:

  1. one is using this.state and
  2. another one is this.setState.

We use the first method to initialize the state in the constructor, and the second method is used for the rest of the time.

Initialize State in the Constructor One way is to initialize the state is in the constructor. As we discussed earlier constructor is the first method to be called when React instantiates the class. This is the perfect place to initialize the state for the component because the constructor is called before the React renders the component in the UI.

class WithConstructor {
   
  constructor() {
   this.state = {
     name: "StackOverflow"
    }
  }
}

Initialize State Without Constructor Another way of initializing state in React is to use the Class property. Once the class is instantiated in the memory all the properties of the class are created so that we can read these properties in the render function.

class WithoutConstructor {
   
  state = {
   name: "StackOverflow"
  }
}
Jimmy
  • 995
  • 9
  • 18
  • 1
    The question is for how to do this in *functional* components. Your answer is correct for *class* components. – mortb May 20 '22 at 09:07