【问题标题】:React: "Warning: Received NaN for the `children` attribute" when using useReducer反应:“警告:使用 useReducer 时收到 `children` 属性的 NaN”
【发布时间】:2020-05-14 03:27:18
【问题描述】:

我正在学习如何在 React 中使用Reducer,当我尝试使状态计数和数字相互交互时收到此错误消息:“警告:children 属性收到 NaN”

import React, { useReducer } from 'react'

const initialState = {
    count: 0,
    number: 2,
}

const countReducer = (state, action) => {
    switch (action.type) {
        case 'INCREMENT':
            return { count: state.count + state.number }

        case 'DECREMENT':
            return { count: state.count - state.number }

        default:
            return state
    }
}

const Reducer = () => {

    const [state, dispatch] = useReducer(countReducer, initialState)


    return (
        <div>
            <button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
            <button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button>
            <h1>{state.count}</h1>
        </div>
    )
}

export default Reducer

我第一次递增时,它工作正常,它会递增或递减 2。但是,我第二次点击时,我得到了那个错误。

有人能告诉我这是为什么吗?

【问题讨论】:

    标签: reactjs


    【解决方案1】:

    当您从 reducer 返回时,您并没有替换所有状态值,因此第二次 state.number 未定义。然后,您尝试使用 undefined 进行数学运算,这会导致 NaN 错误。

    改变这个:

    return { count: state.count + state.number }
    

    到这里:

    return { ...state, count: state.count + state.number }
    

    对递减的情况做同样的事情。

    这称为解构,会将您之前的状态复制到新对象中,然后您可以覆盖任何需要更改的内容。

    以下是工作示例:

    const {useState, useReducer} = React;
    
    const initialState = {
      count: 0,
      number: 2,
    }
    
    const countReducer = (state, action) => {
      switch (action.type) {
        case 'INCREMENT':
          return { ...state, count: state.count + state.number }
        case 'DECREMENT':
          return { ...state, count: state.count - state.number }
        default:
          return state
      }
    }
    
    const Example = () => {
      const [state, dispatch] = useReducer(countReducer, initialState)
      
      return (
        <div>
          <button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
          <button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button>
          <h1>{state.count}</h1>
        </div>
      )
    }
    
    ReactDOM.render(<Example />, document.getElementById('root'));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    <div id="root"></div>

    【讨论】:

    • 非常感谢,它完美运行。您介意向我解释为什么“数字”状态不会保持在 2 而是“未定义”吗?这是我唯一不明白的部分。我的意思是,为什么它不保留我给它的初始值 2?
    • reducer 函数的返回值是新状态(整个新状态)。它不会自动将返回值与以前的值合并。因此,如果您不返回之前状态的任何部分,它就会丢失。这就是为什么您还必须将default 设置为返回state。如果没有找到匹配项,您的整个状态将丢失。
    • 我认为人们被抛弃是因为基于类的setState确实将新值与旧值合并。但是有了钩子,useStateuseReducer 都不会合并,它们都要求您在更新时替换所有状态。
    • 我现在遇到的问题是我不知道如何在 API 调用之后保持计数。在这种情况下,'...state' 语法将无济于事。在这种情况下我该怎么办?
    • 我不太清楚你的意思。 API 调用本身不会影响状态值。您是否正在使用返回值来影响状态?
    猜你喜欢
    • 2021-12-16
    • 1970-01-01
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    • 2019-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多