使用长 运行 任务反应 useEffect 挂钩并合并状态

React useEffect hook with long running task and merge state

我有一个用户可以使用拖放上传文件的场景。

我使用一个带有空 depedency 数组的效果来设置一个 RXJS 订阅来处理丢弃的文件和上传时间:

const [attachments, setAttachments] = useState([])

useEffect(() => {
    ...
    fileUploadSubject.subscribe(newAttachments => {
       setAttachments([...attachments,newAttachments])
    })
    ...
    return () => {
      subscriptions.forEach(s => {
        s.unsubscribe()
      })
    }
},[])

问题是效果依赖于 attachments 以及 setAttachments 函数。

如果我将 attachments 添加到依赖项数组,我将取消订阅现有的上传。此外,attachment 状态由于其关闭而不会在效果内部更新。

我该如何处理这种情况?我想过很多方法,但似乎找不到简单的方法。

If I add attachments to the dependency array I will unsubscribe to the existing uploads

不知道为什么取消订阅,不熟悉fileUploadSubject.subscribe

Also attachment state is not updated inside the effect due to its closure

您可以 useReducer 而不是 useState,这样您就不需要依赖效果中的状态。
也许是这样的:

function reducer(state, action) {
  switch (action.type) {
    case "ADD_ATTACH":
      return [...state, action.payload];
    default:
      throw new Error();
  }
}

function App() {
  const [attachments, dispatch] = useReducer(reducer, []);

  useEffect(() => {
    // ...
    fileUploadSubject.subscribe(newAttachments => {
      dispatch({ type: "ADD_ATTACH", payload: newAttachments });
    });
    // ...
    return () => {
      subscriptions.forEach(s => {
        s.unsubscribe();
      });
    };
  }, [/*fileUploadSubject?,  subscriptions? */]);

  return <div>{ /* some UI */ }</div>;
}

我仍然认为你的效果不依赖于任何东西很奇怪,确保 subscriptionsfileUploadSubject 真的不应该在 dependencies 数组中。

useState的setState函数支持functional updates形式:

const [attachments, setAttachments] = useState([])

useEffect(() => {
    ...
    const subscription = fileUploadSubject.subscribe(newAttachments => {
       setAttachments((oldAttachments) => [...oldAttachments, newAttachments])
    })
    ...
    return () => subscription.unsubscribe()
}, [setAttachments, fileUploadSubject])

永远不会改变的函数(即这里的两个)可以在依赖列表中省略,但我更喜欢列出它们以防止忘记一些依赖。有 eslint rules 的难度。