alibaba / hooks

A high-quality & reliable React Hooks library. https://ahooks.pages.dev/
https://ahooks.js.org/
MIT License
14.12k stars 2.73k forks source link

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

Open PalePlain opened 8 months ago

PalePlain commented 8 months ago

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 commented 8 months ago

@crazylxr

crazylxr commented 8 months ago

收到,我看下

lfl-0 commented 3 months ago

这个计划解决吗?

crazylxr commented 3 months ago

这个计划解决吗?

有的

tchen-l commented 1 month ago
ReactDOM.render(<App />, document.getElementById("root"))

改成

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

就正常了

ppYoung commented 2 weeks ago

这个计划解决吗?

有的

当前进度如何 @crazylxr