最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React make useState initial value conditional - Stack Overflow

programmeradmin3浏览0评论

I am trying to set initial state based on data from props.

const Calculate({data}) => {
  const [number, setNumber] = data === 'end' ? useState(5) : useState(0);

  return (...)
}

This gave me an error: React Hook "React.useState" is called conditionally. React Hooks must be called in the exact same order in every component render.

So I decided to update my code with useEffect:

const Calculate({data}) => {
  const [number, setNumber] = useState(0);

  useEffect(() => {
     if (data === 'end') {
       setNumber(5)
     }
   }, []);
} 

However I'd rather not set the state initially to zero if I don't need to.

Alternatively can I solve it by making the initial value conditional?

const Calculate({data}) => {
  const [number, setNumber] = useState(data === 'end' ? 5 : 0);

  return (...)
}

Are there any side effects to this? Why would this work and not my original attempt?

I am trying to set initial state based on data from props.

const Calculate({data}) => {
  const [number, setNumber] = data === 'end' ? useState(5) : useState(0);

  return (...)
}

This gave me an error: React Hook "React.useState" is called conditionally. React Hooks must be called in the exact same order in every component render.

So I decided to update my code with useEffect:

const Calculate({data}) => {
  const [number, setNumber] = useState(0);

  useEffect(() => {
     if (data === 'end') {
       setNumber(5)
     }
   }, []);
} 

However I'd rather not set the state initially to zero if I don't need to.

Alternatively can I solve it by making the initial value conditional?

const Calculate({data}) => {
  const [number, setNumber] = useState(data === 'end' ? 5 : 0);

  return (...)
}

Are there any side effects to this? Why would this work and not my original attempt?

Share Improve this question asked Aug 26, 2021 at 20:39 user2456977user2456977 3,96414 gold badges49 silver badges91 bronze badges 2
  • The idiomatic way to do what you want is const [number, setNumber] = useState(data == 'end' ? 5 : 0) – HaveSpacesuit Commented Aug 26, 2021 at 21:02
  • React is all about pain, have you ever tried super fast and lightweight like baby feather Solid? – user15023244 Commented Aug 26, 2021 at 22:05
Add a comment  | 

3 Answers 3

Reset to default 14

You can use a ternary inside your useState hook and it will work fine. However, it is better to wrap it inside a function expression in the following manner:

const [number, setNumber] = useState(() => data === 'end' ? 5 : 0)

The function expression in above code snippet will be evaluated only once while setting the initial state. There is an upside to wrapping your ternary operator inside the function expression.

Suppose that instead of data === 'end' ? 5 : 0 you want to use the results of an expensive computation to set the initial state, in such a case you can wrap it inside a function expression like:

const [number, setNumber] = useState(() => expensiveFunction())

This is better because () => expensiveFunction() will return a function which will only be evaluated once during the initial render. Whereas if you don't wrap the expensiveFunction inside a function expression, it will be evaluated each time your component renders and block the execution of code until expensiveFunction returns a value.

This approach is also known as Lazy initialization.

Are there any side effects to this? Why would this work and not my original attempt?

No there are no side effects, that is the way to go in your situation. It didn't work in your case because you violated one of the rules of hooks:

Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls. (If you’re curious, we’ll explain this in depth below.)

Initially your useState calls themselves were wrapped inside a condition and that was a problem. That is not the case anymore with your newer approach.

If data can ever change.... The only thing you need to make sure you handle is that the data being passed down is not null, but rather undefined if it doesn't exist.

Your useEffect should have data in the dependency array to re-render the component upon any change.

const Calculate({data = 0}) => {
  const [number, setNumber] = useState(data);

  useEffect(() => {
     setNumber(data)
   }, [data]);
} 
发布评论

评论列表(0)

  1. 暂无评论