hooks icon indicating copy to clipboard operation
hooks copied to clipboard

useRequest 在 React 18 部分场景下不兼容, 存在严重问题

Open PalePlain opened this issue 10 months ago • 5 comments

link: https://github.com/alibaba/hooks/issues/new

useRequest:

Fetch.ts 文件: image

useRequestImplement.ts 文件: image

当触发用户交互行为, 如拖拽行为时:

React 17 会按照下列顺序执行:

  1. 依照 Effect 链条顺序优先执行 drag文件 Effect Cleanup
  2. 接着执行 useRequest Hook Effect Cleanup, 此时会触发 useRequestImplement.ts useUnmount 回调函数, 即 fetchInstance.cancel(), 而执行 fetchInstance.cancel() 后会使得 this.count + 1, 此时 this.count 值为 1
  3. 接着触发 drag文件 useRequest 返回的 run 函数, 此时 this.count 再次 + 1, 值为 2, 因此 currentCount 的值也为 2, 因此会按照预期执行 onSuccess 回调函数

符合预期

React 18 执行顺序 :

  1. 优先触发拖拽行为, 即 drag文件 useRequest 返回的 run 函数, 此时 this.count + 1, 值为 1, 因此 currentCount 的值为 1
  2. 执行异步逻辑 const res = await servicePromise; 触发 异步可中断更新 3.. 时间切片 调度其他优先级任务, 执行 Effect 链条 Cleanup: useDragPreCheck Hook Effect Cleanup -> useRequest Hook Effect Cleanup, 此时执行 fetchInstance.cancel(), this.count + 1, 此时 this.count 值为 2
  3. 异步 行为完成后, 回到上下文继续执行逻辑, 此时判断 currentCount !== this.count 成立, currentCount 由于闭包存在, 值为1, 而 this.count 值为 2, 因此返回了 new Promise(() => {}); 导致 onSuccess 未被执行

在页面中的表现则为 onSuccess 未触发, loading 不消失, 数据未处理

相关 demo (React 18.2.0 + ahooks 3.7.10) : https://is.gd/lZJgyH

将一个节点拖拽到另一个容器中, 表现为 loading 不消失; 而将 react 版本更换为 react 17 后则表现正常;

PalePlain avatar Apr 07 '24 02:04 PalePlain

@crazylxr

PalePlain avatar Apr 07 '24 02:04 PalePlain

收到,我看下

crazylxr avatar Apr 08 '24 01:04 crazylxr

这个计划解决吗?

lfl-0 avatar Aug 27 '24 01:08 lfl-0

这个计划解决吗?

有的

crazylxr avatar Aug 29 '24 01:08 crazylxr

ReactDOM.render(<App />, document.getElementById("root"))

改成

const root = createRoot(document.getElementById("root"));
root.render(<App />);

就正常了

tchen-l avatar Oct 09 '24 05:10 tchen-l