首页 > 解决方案 > 带有 useState 的自定义反应钩子始终重置为其初始值

问题描述

我正在尝试创建一个自定义反应挂钩,以将 9 个元素的状态保存在一个对象中,无论是真还是假。

let pads = {
  Q: false,
  W: false,
  E: false,
  A: false,
  S: false,
  D: false,
  F: false,
  Z: false,
  X: false,
  C: false,
};

export default () => {
  const [padsPlaying, setPadsPlaying] = useState(pads);
  return {
    padsPlaying,
    setPlayState: (element, state) => {
      setPadsPlaying({ ...state, [element]: true });
    },
  };
};

在我的组件中,我导入了钩子并像这样调用它:

  const { padsPlaying, setPlayState } = usePlayState();

  const playSound = (element) => {
   
 // do some other stuff and in the end:

    setPlayState(element.id, padsPlaying);
  };

它起作用了,一个 element.id 的Q返回状态 with Q:trueand all other false。但是,如果我再次运行该函数,它会重置Q为其初始值false并且新元素是true. 有人可以指出我正确的方向吗?我尝试了设置播放状态和初始化状态的不同组合,但我觉得我只是在开枪,我在这里错过了什么?

编辑:我正在使用该状态来呈现带有 isPlaying 属性的组件列表,true或者false

  const makePads = preset[0].sounds.map((sound, i) => (
    <DrumPad
      key={sound.id}
      id={sound.name}
      name={sound.name}
      source={sound.source}
      trigger={sound.trigger}
      isPlaying={padsPlaying[i]}
    />
  ));

解决了我对使用旧状态的地方感到困惑,现在钩子看起来像这样并且它正在工作:)

export default () => {
  const [padsPlaying, setPadsPlaying] = useState(initialPads);
  const setPlayState = (id) => {
    setPadsPlaying((state) => {
      console.log(id);
      return { ...state, [id]: true };
    });
  };
  return [padsPlaying, setPlayState];
};

标签: javascriptreactjsreact-hookssetstate

解决方案


我认为您访问状态不正确,但我不确定,因为您没有所有代码来查看您如何访问状态。

我从您的代码中重新创建了一个小示例

let pads = {
  Q: false,
  W: false,
};

const usePlayState = () => {
  const [padsPlaying, setPadsPlaying] = useState(pads);

  const setPlayState = (element, state) => {
    setPadsPlaying({ ...state, [element]: true });
  }

  return [
    padsPlaying,
    setPlayState,
  ];
};


function Testme() {

  const [padsPlaying, setPlayState] = usePlayState();


  useEffect(() => {
    console.log(padsPlaying) // the proper way to access the new updated state is here
  })

  return (<div>

    <button onClick={() => {
      setPlayState('Q', padsPlaying);
      // console.log(padsPlaying); // => Q still false because you still have the old stale state
    }}>
      Q
    </button>

    <button onClick={() => {
      setPlayState('W', padsPlaying);
      // console.log(padsPlaying); // => W still false because you still have the old stale state
    }}>
      W
    </button>

  </div>)
}

我指出了访问新状态的正确方法在哪里,useEffect哪个更等效ComponentDidMount,如果您立即访问该状态,您将获得旧状态,state并且您会发现Q从内部读取值时仍然为假useEffect将给出新的实际价值


推荐阅读