简体   繁体   English

React Hooks setState的意外结果

[英]Unexpected result with React Hooks setState

I am getting some unexpected results. 我得到了一些意想不到的结果。 Looking at that 看着那个

import React from 'react';
import PropTypes from 'prop-types';

const propTypes = {
  fooList: PropTypes.array
};

const defaultProps = {
    fooList: [
        { active: false }, 
        { active: false }
    ];
};

const FooBar = ({
  fooList
}) => {
  const [state, setState] = React.useState(fooList);
  const onClick = (entry, index) => {
    entry.active = !entry.active;
    state[index] = entry;
    console.log('#1', state) // <- That loggs the new State properly!
    setState(state);
  }
  console.log('#2', state) // <- That does not log at after clicking on the text, only after the initial render
  return state.map((entry, index) => {
    return <p
      onClick={() => onClick(entry, index)}
      key={index}>
      {`Entry is: ${entry.active ? 'active' : 'not active'}`}
    </p>
  })
}

FooBar.defaultProps = defaultProps;
FooBar.propTypes = propTypes;
export default FooBar;

I expect on every click the text in the <p /> Tag to change from Entry is: not active to Entry is: active . 我希望每次点击<p />标记中的文本从Entry is: not active变为Entry is: active

Now, I am not sure if I can simply alter the state like this 现在,我不确定是否可以像这样简单地更改状态

state[index] = entry;

Using a class extending React.Component , this wouldn't work. 使用扩展React.Component的类,这将无法工作。 But maybe with React Hooks? 但是也许有React Hooks? And then, I am not sure if I can use hooks in a map() . 然后,我不确定是否可以在map()使用钩子。

When you use state[index] = entry; 当您使用state[index] = entry; , you are mutating the state but the state reference does not change, and so React will not be able to tell if the state changed, and will not re-render. ,您正在改变状态,但是状态引用不会更改,因此React将无法判断状态是否已更改,并且不会重新呈现。

You can copy the state before mutating it: 您可以在更改状态之前复制状态:

  const onClick = (entry, index) => {
    entry.active = !entry.active;
    const newState = [...state];
    newState[index] = entry;
    console.log(newState) // <- That loggs the new State properly!
    setState(newState);
  }

I would also consider maybe changing up your design a little https://stackblitz.com/edit/react-6enuud 我还会考虑也许会稍微改变一下您的设计https://stackblitz.com/edit/react-6enuud

rather than handling each individual click out side, if it is just for display purposes, then it can be easier to encapsulate in a new component: 而不是处理每个单独的点击侧,如果只是用于显示目的,则可以更容易地封装到新组件中:

const FooBarDisplay = (entry) => {
  const [active, setActive] = useState(entry.active);
  const onClick = () => {
    setActive(!active);
  }
  return (<p onClick={() => onClick()}>
    {`Entry is: ${active ? 'active' : 'not active'}`}
  </p>
  )
}

Here you can make handling state easier, and avoid mutating arrays. 在这里,您可以简化状态处理,并避免对数组进行变异。

Simpler parent: 较简单的父项:

const FooBar = ({
  fooList = [
    { active: false },
    { active: false }
  ]
}) => fooList.map((entry, i) => <FooBarDisplay key={i} entry={entry} />);

I've just moved default props to actual default argument values. 我刚刚将默认道具移到了实际的默认参数值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM