【问题标题】:How to correctly implement a props callback function in the useEffect hook如何在useEffect hook中正确实现props回调函数
【发布时间】:2020-10-29 15:12:16
【问题描述】:

我想使用useEffect() 来检测状态值的变化,并使用作为道具接收的回调函数将该值传递给父组件。如果不禁用 eslint 缺少依赖项警告,我想不出办法做到这一点。我在子组件和那个孩子的孩子上都有这个问题。

这里是父实现:

const updateValues = (newValues) => {
  setValues({ ...values, ...newValues });
};

<GeneralUpdates onUpdate={updateValues} />

这是第一个孩子(GeneralUpdates):

const [values, setValues] = useState({
    name: '',
    description: '',
  });

// This handles form input changes
const handleChange = (prop) => (event) => {
  setValues({ ...values, [prop]: event.target.value });
};

useEffect(() => {
  onUpdate(values);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [values]);

<FilesUpload handleChange={onUpdate}/>

这是孩子的孩子(FilesUpload):

const [featuredPhotos, setFeaturedPhotos] = useState([]);

useEffect(() => {
  handleChange({ featuredPhotos });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [featuredPhotos]);

handleChange 添加为依赖项会导致无限的重新渲染循环。我已经尝试了所有我能找到的解决方案,但这里肯定遗漏了一些东西。

【问题讨论】:

  • 您可以禁用,否则您将不得不记住 handleChange,因为该函数值可能会在每次重新渲染时不断变化,从而再次触发 useEffect
  • 第一个孩子中的setValues 来自哪里?如果您可以在代码沙箱或代码笔上添加一个小示例,这将对其他人有很大帮助
  • 我已经添加了它@RaheelRiaz,还添加了对我有用的解决方案作为答案,但绝对有兴趣获得更多洞察力。

标签: reactjs react-hooks create-react-app eslint


【解决方案1】:

一位同事帮我找到了解决方案——将命名函数传递给 useEffect 而不是匿名函数:

const updateCallback = () => {
    onUpdate(values);
  };

useEffect(updateCallback, [values]);

【讨论】:

  • 该死,这应该是 useEffect 的 react 文档的一部分,它是如此常见的模式。
  • 需要注意的是,这基本上是禁用了依赖列表的 eslint 检查。例如,如果您从 deps 中删除 values 参数,它不会抱怨。
【解决方案2】:

如果您 100% 了解自己在做什么,则针对此特定规则禁用 eslint 没有任何问题。

但是,如果父级是功能组件,您仍然可以通过使用 useCallback hook 来解决此问题,而不禁用 eslint,因为 handleChange 函数从父级传递过来

// in parent
const handleChange = useCallback(({featuredPhotos}) => {
    // Do what you want to do here
}, []);

如果 parent 不是函数式组件,请确保在将箭头函数作为道具传递时没有在渲染中使用箭头函数,你应该没问题

handleChange = ({featuredPhotos}) => {
   ...
}

render() {
   return (
       <Child handleChange={this.handleChange} />
   )
}

编辑:

对于您的情况,您可以使用 useCallback 来更新实现 updateValue 函数,并在其中使用函数 setState

const updateValues = useCallback((newValues) => {
  setValues(prevValues => ({ ...prevValues, ...newValues }));
}, []);

【讨论】:

  • 应该注意,只有当父组件也是功能组件时,这才有效。
  • 这很有帮助,但我不确定如何在我的情况下实现它,因为正在讨论的两者之间有一个组件。结构更像:带有handleChange回调的功能性父组件->带有useEffect的功能性组件处理表单输入->功能性组件处理featuredPhotos。此外,当我按照描述实现 useCallback 挂钩时,我收到相同的缺失 deps 错误。
  • 请分享handleChange在parent中的实现以及你如何将它作为props传递给孩子
  • 我更新了我的答案,如果useEffect只需要调用onUpdate,你的答案会起作用,但如果它有更多的逻辑,它会给你带来麻烦。
【解决方案3】:

我正在添加另一个解决方案,这也让 eslint 感到高兴:

const callback = useRef();
callback.current = onUpdate;     

useEffect(() => {
  callback.current(values);
}, [values, callback]);

【讨论】:

    猜你喜欢
    • 2020-08-07
    • 2019-11-01
    • 2020-12-29
    • 2020-11-22
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    • 2021-09-24
    相关资源
    最近更新 更多