简体   繁体   English

当组件可以随时卸载时,如何使用 React 管理 useEffects 中的竞争条件风险?

[英]How to manage the risk of race conditions in useEffects when a component can un-mount at any time, with React?

Using TypeScript 4, React 17 (current versions at the time I'm writing these lines).使用 TypeScript 4、React 17(我写这些行时的当前版本)。

Let say I have the following component.假设我有以下组件。

This component is behind a React Navigation conditional stack navigator.该组件位于 React Navigation 条件堆栈导航器之后。 This mean that if the user un-connect, the component will be automatically unmounted and the with the whole UI, showing the login screen instead.这意味着如果用户取消连接,该组件将自动卸载并与整个 UI 一起显示,而是显示登录屏幕。

This is managed by such code in the app's root navigator:这是由应用程序根导航器中的此类代码管理的:

user ? (
    <RootStack.Screen name="Home" component={HomeScreen} />
) : (
    <RootStack.Screen name="Login" component={LoginScreen} />
)

Here is a component that print on the home screen.这是在主屏幕上打印的组件。

I had some issues in another project and a friend of mine recommended to always put this un-mounting condition when a component un-mount with a risk of race condition.我在另一个项目中遇到了一些问题,我的一个朋友建议在组件卸载时始终处于这种卸载状态,并且存在竞争条件的风险。

I have some race conditions issues but adding un-mounting on all the components did not solved it so far.我有一些竞争条件问题,但到目前为止,在所有组件上添加卸载都没有解决。

Is my friend right that I shall continue to put these un-mounting or is it un-needed for such simple and synchronous cases as the following component?我的朋友是否应该继续将这些卸载或者像以下组件这样简单和同步的情况下不需要它?

interface Props {
    prop1: number
}

const MyFunctionalComponent: FC<Props> = ({prop1 = 0}: Props) => {

    const [stateVariable, setStateVariable] = useState<string>('initial value')

    useEffect(() => {
        let mounted = true
        if (mounted) {
          // We are synchronous, no await there.
          const newStateVariable: string = stringify(prop1)
          setStateVariable(newStateVariable)
        }
        return (): void => {
          mounted = false
        }
    }, [prop1])

    return <Text>{ stateVariable }</Text>
}

What do you use and know about this ?您对此有何用途和了解?

Thanks谢谢

You don't have to use useEffect hook's clean up to do this.您不必使用useEffect钩子的清理来执行此操作。

useEffect hook is run when dependency list is changed. useEffect钩子在依赖列表改变时运行。 Which is like componentDidUpdate in the React class components.这就好比componentDidUpdateReact类组件。

useEffect(() => {
   // This runs every time the prop1 changes

 return () => {
  // This runs every time the prop1 changes
 };
}, [prop1]);

If you just have empty array for dependency list then it works like componentDidMount in the React class components.如果你只是空数组的依赖列表,然后它就像componentDidMountReact类组件。

useEffect(() => {
   // This runs when component mounts
   // see there is no dependency passed for this

 return () => {
  // This runs when component un mounts
  // Do your cleanup here as it is run only on unmount
 };
}, []);

useEffect hook runs all the when its own state or props change if neither empty array or dependency list is passed.如果未传递空数组或依赖项列表,则useEffect钩子会在其自己的stateprops更改时运行所有内容。

useEffect(() => {
   // Runs every time the component renders

});

I guess now it is now clear about your case.我想现在你的案子已经很清楚了。

You don't have to use the mounted variable itself.您不必使用mounted变量本身。 Every time when your prop1 changes the stateVariable will get updated.每次当您的prop1更改时, stateVariable都会更新。

const MyFunctionalComponent: FC<Props> = ({prop1 = 0}: Props) => {

    const [stateVariable, setStateVariable] = useState<string>('initial value')

    useEffect(() => {
       // We are synchronous, no await there.
       const newStateVariable: string = stringify(prop1)

       setStateVariable(newStateVariable)
    }, [prop1])

    return <Text>{ stateVariable }</Text>
}

Some of the cases when you need to use the cleanup function需要使用cleanup功能的一些情况

  1. To removeEventListener on document or window or any other subscription that functional component has made. removeEventListener documentwindow上的事件removeEventListener或功能组件所做的任何其他订阅。

  2. To dispatch to cleanup store(if needed) if you are using redux.如果您使用的是 redux,则分派到清理商店(如果需要)。

  3. To clearInterval or clearTimeout if there are any.如果有的话,要clearIntervalclearTimeout

Some of the cases where not use the cleanup function不使用cleanup功能的一些情况

  1. To set the state of the functional component that is un mounting.设置未挂载的功能组件的状态。

  2. In the case like your question (not needed at all).在像你的问题的情况下(根本不需要)。

In the case of MyFunctionalComponent , you should call useMemo() instead of useState() and useEffect() :MyFunctionalComponent的情况下,您应该调用useMemo()而不是useState()useEffect()

interface Props {
    prop1: number
}

const MyFunctionalComponent: FC<Props> = ({ prop1 = 0 }: Props) => {
    const computedVariable = useMemo(() => {
        return stringify(prop1)
    }, [prop1])

    return <Text>{ computedVariable }</Text>
}

useState() should only be necessary if you need a stateful value. useState()仅在您需要有状态值时才需要。 In the example you provided, stateVariable is purely dependent on prop1 , without any delay, so it doesn't actually need to be stateful at all.在您提供的示例中, stateVariable完全依赖于prop1 ,没有任何延迟,因此它实际上根本不需要有状态。 useMemo() is technically also a stateful hook, but is only there to avoid unnecessary repetition of expensive computations when the inputs are unchanged. useMemo()在技​​术上也是一个有状态的钩子,但只是为了在输入不变时避免不必要的重复昂贵的计算。

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

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