React Hooks setState的意外结果

时间:2019-09-10 08:57:22

标签: javascript reactjs react-hooks

我得到了一些意想不到的结果。 看着那个

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;

我希望每次点击<p />标记中的文本都会从Entry is: not active变为Entry is: active

现在,我不确定是否可以像这样简单地更改状态

state[index] = entry;

使用扩展React.Component的类,此操作将无效。但是也许有React Hooks?然后,我不确定是否可以在map()中使用钩子。

2 个答案:

答案 0 :(得分:4)

使用state[index] = entry;时,您是在改变状态,但是状态引用没有改变,因此React将无法判断状态是否改变,并且也不会重新呈现。

您可以在更改状态之前复制状态:

  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);
  }

答案 1 :(得分:0)

我还会考虑也许对您的设计进行一点https://stackblitz.com/edit/react-6enuud

如果仅出于显示目的,而不是处理每个单独的点击侧,则可以更容易地将其封装在新组件中:

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

在这里,您可以使处理状态更加容易,并避免对数组进行变异。

简单的父母:

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

我刚刚将默认道具转移到实际的默认参数值。