无法获取函数内部更新的挂钩值

时间:2020-09-09 14:47:24

标签: reactjs react-native react-hooks setstate

未获得由eventListener触发的函数中状态的更新值。甚至尝试过使用背景计时器。怎么了?

displayIncomingCall() // this function gets called from UI.
const callApp = () => {
  const [calls, setCalls] = useState({});

  const addCall = (key, value) => {
    setCalls({ ...calls, [key]: value });
  };

  const displayIncomingCall = number => {
    const callUUID = getCurrentCallId();
    addCall(callUUID, number);
    ...
  };

  const onAnswerCall = () => {
    console.log('=== onAnswerCall ::: ===', calls); <--- always initial value. Not getting updated one.
  }

  useEffect(() => {
    console.log('=== useEffect ::: ===', calls); // getting updated value
  }, [calls]);

  useEffect(() => {
    RNCallKeep.addEventListener('answerCall', onAnswerCall);
    return () => {
      RNCallKeep.removeEventListener('answerCall', onAnswerCall);
    };
  }, []);

  console.log('=== parent ::: ===', calls); // getting updated value

  return (...)
}

3 个答案:

答案 0 :(得分:1)

onAnswerCall仅在useEffect回调中被引用,而useEffect回调具有一个空的依赖项数组,因此它仅在初始安装时运行。每当调用onAnswerCall时,它可以看到的calls的绑定就在旧的闭包中。

使用ref代替状态:

const callsRef = useRef({});
const addCall = (key, value) => {
  callsRef.current[key] = value;
};
const onAnswerCall = () => {
  console.log('=== onAnswerCall ::: ===', callsRef.current);
}

如果calls 需要处于状态,以便其更改导致重新渲染,那么您可以同时使用 状态和ref,并在调用setCalls时分配给ref,或者可以从useEffect中删除依赖项数组,从而在每个渲染器上为RNCallKeep添加和删除侦听器。

答案 1 :(得分:1)

反应挂钩状态不会保留任何状态数据,您必须使用useCallback以及set*状态函数中特权的前一个状态才能保持状态:

const callApp = () => {
  const [calls, setCalls] = useState({});

  const addCall = (key, value) => {
    // Use previous state provided to update the state
    setCalls(calls => ({ ...calls, [key]: value }));
  };

  const displayIncomingCall = number => {
    const callUUID = getCurrentCallId();
    addCall(callUUID, number);
    ...
  };

  //  Use useCallback to keep up  with the  state
  const onAnswerCall = useCallback(() => {
    console.log('=== onAnswerCall ::: ===', calls); <--- Will get updated
  }, [calls]);

  useEffect(() => {
    console.log('=== useEffect ::: ===', calls); // getting updated value
  }, [calls]);

  useEffect(() => {
    RNCallKeep.addEventListener('answerCall', onAnswerCall);
    return () => {
      RNCallKeep.removeEventListener('answerCall', onAnswerCall);
    };
  }, [onAnswerCall]);

  console.log('=== parent ::: ===', calls); // getting updated value

  return (...)
}

答案 2 :(得分:1)

您的事件监听器回调在bc的初始状态下关闭。将其添加为效果的依赖项,并且每次其值更改时都应注册一个新的侦听器(并删除旧的侦听器)。

编辑:实际上,您应该将整个calls函数移到效果中,因为它仅在此处使用:

onAnswerCall