无法对未安装的子组件执行 React 状态更新?

Can't perform a React State update on unMounted child component?

收到此警告:

Can't perform a React state update on unmounted component. This is a no-op...

它是由 child component 引起的,我不知道如何让它消失。

请注意,我已经阅读了很多关于为什么会发生这种情况的其他帖子,并且了解基本问题。但是,大多数解决方案建议在 componentWillUnmount 样式函数中取消订阅(我正在使用 react hooks

我不知道这是否指向我对 React 的一些更大的基本误解,
但我基本上是这样的:

import React, { useEffect, useRef } from 'react';
import Picker from 'emoji-picker-react';

const MyTextarea = (props) => {

  const onClick = (event, emojiObject) => {
    //do stuff...
  }

  const isMountedRef = useRef(true);

  useEffect(() => {
    isMountedRef.current = true;
  });

  useEffect(() => {
    return () => {
      console.log('will unmount');
      isMountedRef.current = false;
    }
  });

  return (
    <div>
      <textarea></textarea>
      { isMountedRef.current ? (
          <Picker onEmojiClick={onClick}/>
        ):null
      }
    </div>
  );
};

export default MyTextarea;

(tl;dr) 请注意:

更多上下文

我不太确定你的问题到底是什么(是你无法摆脱警告还是 <Picker> 总是呈现或从不呈现),但我会尝试解决我看到的所有问题。

首先,您不需要根据是否安装 MyTextArea 来有条件地渲染 <Picker>。由于组件仅在挂载后呈现,因此 <Picker> 如果其所在的组件尚未挂载则永远不会呈现。

话虽如此,如果您仍想跟踪组件何时安装,我建议不要使用钩子,并使用 componentDidMountcomponentWillUnmount 以及 setState()反而。这不仅会让您更容易理解您的组件的生命周期,而且您使用挂钩的方式也存在一些问题。

现在,您的 useRef(true) 会在组件初始化时将 isMountedRef.current 设置为 true,因此即使在安装之前也是如此。 useRef()componentDidMount() 不同。

在安装组件时使用'useEffect()'将isMountedRef.current切换为true也不起作用。虽然它会在安装组件时触发,但 useEffect() 用于副作用,而不是状态更新,因此它不会触发重新渲染,这就是为什么当您设置 useRef(null) 时组件从不渲染的原因.

此外,您的 useEffect() 挂钩将在您的组件每次更新时触发,而不仅仅是在它安装时触发,并且您的清理函数(正在返回的函数)也会在每次更新时触发,而不仅仅是在它加载时触发卸载。因此,在每次更新时,isMountedRef.current 都会从 true 切换到 false,然后再切换回 true。但是,none 这很重要,因为无论如何组件都不会重新渲染(如上所述)。

如果你真的需要使用 useEffect() 那么你应该将它组合成一个函数并用它来更新状态,以便它触发重新渲染:

const [isMounted, setIsMounted] = useState(false);  // Create state variables

useEffect(() => {
  setIsMounted(true);  // The effect and clean up are in one function
  return () => {
    console.log('will unmount');
    setIsMounted(false);
  }
}, [] // This prevents firing on every update, w/o it you'll get an infinite loop
);

最后,根据您共享的代码,您的组件不会导致警告,因为您的代码中的任何地方都没有状态更新。您应该检查选择器的回购协议是否有问题。

编辑:警告似乎是由您的 Picker 包引起的,并且已经存在问题 https://github.com/ealush/emoji-picker-react/issues/142