简体   繁体   English

反应:在内部组件中使用回调或定义?

[英]React: to useCallback or define in inner component?

I have two components, such that they are:我有两个组件,它们是:

const ChildOn = (/*...*/) => {
  //...
}

const Parent = () => {
  const [is42, setIs42] = useState(true)

  return (is42 ? <ChildOff ... > : <ChildOn ... />)
}

The definition of ChildOff is no important. ChildOff的定义并不重要。

I want to define them as either of the following, yet I can't decide which:我想将它们定义为以下任何一种,但我无法决定是哪一种:

  1. Declares functions used in children, based on a variable/function in the parent, inside each child.基于父级中的变量/函数,在每个子级内部声明子级使用的函数。

     type ChildOnProp = { setIs42: Dispatch<SetStateAction<boolean>> }; const ChildOn = ({ setIs42 }: ChildOnProp) => { const f1 = () => { setIs42(true); }; return <Text onPress={f1} />; }; const Parent = () => { return is42 ? <ChildOff setIs42={setIs42} /> : <ChildOn setIs42={setIs42} />; };
  2. Defines functions used by children, inside the parent.在父级内部定义子级使用的函数。

     type ChildOnProps = { func: () => void } const ChildOn = ({ func }: ChildOnProps) => { return <Text onPress={func} /> } const Parent = () => { const [is42, setIs42] = useState(true) const f1 = useCallback(() => { setIs42(true) }) const f2 = useCallback(() => { setIs42(false) }) return (is42 ? <ChildOff func={f2} /> : <ChildOn func={f1} />) }

While (1) is much prettier to me, (2) seems a lot more efficient.虽然(1)对我来说更漂亮,但(2)似乎更有效率。 Yet I don't know if I'm apt to judge that, since I've read many articles on React contradicting each other on when it's best to use useCallback .然而我不知道我是否倾向于判断这一点,因为我已经阅读了许多关于 React 的文章,它们在何时最好使用useCallback相互矛盾。

The React community warns against useless memoizing as it could add complexity without any of the benefits in some situations. React 社区警告不要使用无用的记忆,因为在某些情况下它可能会增加复杂性而没有任何好处。

In this case, I think it's worth memoizing the callbacks since it will reduce the number of unnecessary renders of the child components, which otherwise could have negative impact, or even introduce issues down over time.在这种情况下,我认为值得记住回调,因为它会减少子组件的不必要渲染的数量,否则可能会产生负面影响,甚至会随着时间的推移引入问题。

To do this, there's a common pattern of creating a custom hook, often called useToggle , which memoize common setters.为此,有一种创建自定义钩子的常见模式,通常称为useToggle ,它可以记忆常见的 setter。

import {useState, useMemo} from 'react';

export function useToggle(initialValue = false) {
  const [value, setValue] = useState(initialValue);

  // Defined once, so guaranteed stability
  const setters = useMemo(() => ({
    toggle: () => setValue(v => !v),
    setFalse: () => setValue(false),
    setTrue: () => setValue(true),
    setValue,
  }), [setValue]);

  // Defined each time the value changes, so less than every render.
  return useMemo(() => ({
    ...setters,
    value
  }), [value, setters]);
}

This can be used in the parent as such:这可以在父级中使用:

const Parent = () => {
  const { value: is42, setTrue, setFalse } = useToggle(true);
  return (is42 ? <ChildOff func={setFalse}> : <ChildOn func={setTrue} />);
}

TypeScript will infer all the types automatically, so it works out of the box. TypeScript 将自动推断所有类型,因此它开箱即用。


If there's multiple state values that need a toggle callback, we can easily identify each one by not destructuring.如果有多个状态值需要切换回调,我们可以通过不解构轻松识别每个状态值。

const firstState = useToggle(true);
const secondState = useToggle(true);
//...
return (
  <>
    <Foo onClick={firstState.toggle} />
    <Bar onClick={secondState.toggle} />
  </>
);

As a reference, here's a simpler implementation from Shopify .作为参考,这是Shopify 的一个更简单的实现 As for memoizing too much or too little, Meta (Facebook) is apparently experimenting with memoizing everything by default at transpile time, so that devs wouldn't have to think about it.至于记忆过多或过少,Meta(Facebook)显然正在尝试在编译时默认记忆所有内容,这样开发人员就不必考虑它了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM