React useEffect 清理函数依赖于 async await 结果

React useEffect cleanup function depends on async await result

我有一个反应组件,它异步获取一些资源,然后订阅资源变化。

问题是清除函数不在这个资源的关闭中:

useEffect(() => {
  const onResourceChange = () => { 
    console.log('resource changed');
  };

  getSomeResource().then(resource => {
    resource.subscribe(onResourceChange);
  });

  return () => {
    resource.unsubscribe(onResourceChange); // Error! resource is undefined
  }
}, []);

由于在 useEffect 中使用异步函数是不允许的,在 useEffect 的清理函数中取消订阅此资源的最佳方法是什么?

这是一个解决方案,可能是丑陋的...但仍然是一个解决方案:)

useEffect(() => {
    const onResourceChange = () => { 
        console.log('resource changed');
    };

    let data = {};

    getSomeResource().then(resource => {
        data.resource = resource;
        resource.subscribe(onResourceChange);
    });

    return () => {
        data.resource && data.resource.unsubscribe(onResourceChange); // Error! resource is undefined
    };
}, []);

我看到这里有两个 "side effects"。

  1. 获取资源(需要发生一次,依赖[]
  2. Subscribe/unsubscribing 回调(需要发生在资源变化、依赖、[resource]

所以我

  1. 将它们分成两个 "effects"(步骤,每个处理一个副作用)
  2. 并将其提取到自定义挂钩中
    function useResource() {
        const [resource, setResource] = useState(undefined)

        const onResourceChange = () => console.log('resource changed');

        // Get the resource, initially.
        useEffect(() => {
          getSomeResource(setResource)
        }, [])

        // When the resource is retrieved (or changed),
        // the resource will subscribe and unsubscribe
        useEffect(() => {
          resource.subscribe(onResourceChange)
          return () => resource.unsubscribe(onResourceChange)
        }, [resource])
    }

    // Use it like this
    function App() {
        useResource()

        return <>your elements</>
    }

如你所见,第一个useEffect只负责获取"resource",而第二个useEffect负责un/subscribing回调。

并查看每个useEffect中的deps列表(前者为空[]而后者依赖[resource]