【问题标题】:ReactJS - prevState in the new useState React hook?ReactJS - 新的 useState React 钩子中的 prevState?
【发布时间】:2019-09-13 08:26:57
【问题描述】:

我真的很喜欢新的React hooks,并且我经常将它们用于我正在进行的项目。我遇到了一种情况,我想在 useState 挂钩中使用 prevState,但我不确定如何执行此操作。

我尝试过类似的方法,但编译失败。

const [ someState, setSomeState ] = useState( new Map() )
setSomeState( prevState.someState.set( key, value ) )

(顺便说一句,这是映射一组复选框以跟踪被选中的复选框)

我正在尝试遵循此示例 here,但未使用 setState 函数。

感谢您的帮助!

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案1】:

    来自useStatestate updater 提供了一个回调模式,它返回您可以用来更新当前状态的先前状态

    const [ someState, setSomeState ] = useState( new Map() )
    setSomeState(prevState => prevState.set( key, value ) )
    

    【讨论】:

    • 嘿,我已经尝试过了,我收到了这个错误Cannot read property 'set' of undefineduseState 钩子有限制吗?
    • 您可能使用的是prevState.someState.set( key, value ) 而不是prevState.set( key, value )
    • 只是为了确认:为什么使用回调中的状态而不是someState?为了避免混乱的并发更新?我只是经常看到这一点,但从来没有出现过技术解释。
    • @EricBurel 您并不总是需要使用函数式 setState,但有时它确实很有用。 This post 解释了类组件的一些细节,但同样适用于功能组件。此外,使用钩子进行功能状态更新对于避免关闭问题也非常有用,因为可以保证为您提供最新状态
    【解决方案2】:

    为了使用Maps,您需要在操作值之前克隆它。否则,它会改变原始的 Map,而 React 无法处理可变的 state

    const handleChange = useCallback(({ target: { name, checked } }) => {
      setCheckbox(prevState => {
        return new Map(prevState).set(name, checked);
      });
    }, []);
    

    更新的工作示例

    【讨论】:

    • 更新了答案以包含一个有效的Map 示例。虽然这可行,但它的性能可能不如其他替代方案(尤其是当 Map 变大时)。
    【解决方案3】:

    对于对象,您可以使用扩展运算符在您的 setState 调用中使用 prevState

    const [object, setObject] = useState({
      firstKey: '',
      secondKey: '',
    });
    
    setObject((prevState) => ({
      ...prevState,
      secondKey: 'value',
    }));
    
    // object = {
    //   firstKey: '',
    //   secondKey: 'value',
    // }
    

    下面的 sn-p 显示了使用prevState 设置对象状态的示例。

    const {useState} = React;
    
    const Example = ({title}) => {
      const initialState = {
        firstKey: 'empty',
        secondKey: 'empty',
        thirdKey: 'not empty',
      }
      const [object, setObject] = useState(initialState);
      
      const withPrevState = () => {
        setObject((prevState) => ({
          ...prevState,
          secondKey: 'not empty',
        }));
      }
    
      return (
        <div>
          <h5>Updates Second key to 'not empty'</h5>
          <p>First key: {object.firstKey}</p>
          <p>Second key: {object.secondKey}</p>
          <p>Third key: {object.thirdKey}</p>
          <button onClick={withPrevState}>
            Update with prevState
          </button>
          <button onClick={() => {setObject({secondKey: 'not empty'})}}>
            Update without prevState
          </button>
          <button onClick={() => {setObject(initialState)}}>
            Reset
          </button>
        </div>
      );
    };
    
    // Render it
    ReactDOM.render(
      <Example />,
      document.getElementById("react")
    );
    <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="react"></div>

    【讨论】:

    • 我终于明白了如何在这个sn-p中使用这个prevstate。谢谢
    • 我相信这会降低性能,因为 React 认为所有状态条目都设置为新的。此外,您正在克隆一个数组,这也可能导致具有许多条目的状态的性能急剧下降。
    【解决方案4】:

    你已经在被破坏的变量中拥有了之前的状态:someState

    所以你可以这样做:

    const [ someState, setSomeState ] = useState( new Map() )
    setSomeState( someState.set( key, value ) )
    

    【讨论】:

    • 不了解 OP 但这解决了我面临的一个问题。谢谢。又聪明!
    【解决方案5】:

    使用这个

    const [setSome, setSomeState] = useState({thing: 'loding', count: 1});
    setSomeState(prev => ({...prev, count: prev.count + 1}));
    

    【讨论】:

      猜你喜欢
      • 2023-01-16
      • 2021-11-25
      • 2021-10-09
      • 2020-10-25
      • 2021-02-19
      • 2023-03-19
      • 2021-02-07
      • 1970-01-01
      • 2021-05-23
      相关资源
      最近更新 更多