ByteNoteByteNote
条件里可以调用这个读取
字

字节笔记本

2026年10月7日 · 约 7 分钟读完

条件里可以调用这个读取

API中转
¥120

对话把 use 介绍成渲染期间读取 Promise,也可以读取上下文,用来代替 useContext。样本是 use(fetchMessage()) 和 use(ThemeContext)。同一段又规定不能写在条件里,必须放在组件顶层,并说它仍是实验。条件调用这一点和这个 API 的规则相反。Promise 在渲染里现场创建,也会让加载反复发生。

条件里可以调用 use,不要在渲染里新造 Promise

样本在渲染时制造了新的 Promise

MessageComponent 里,use 的参数是 fetchMessage() 的返回值。函数写在组件体内,每次渲染都会调用一次,得到一个新的 Promise。use 会在这个 Promise 完成前把渲染交给 Suspense。新的 Promise 没有完成过,加载状态会按渲染次数重新出现。对话建议把 Promise 包进独立函数。包进函数并在渲染时调用,仍然是每次渲染一个新对象。要稳定,应在渲染之外创建,或按请求参数缓存同一份,再把那一份交给 use。

读取上下文的样本是 use(ThemeContext),把结果当成按钮样式。这里没有 Promise。它和 useContext 读的是同一份上下文。对话说可以不必再写 useContext。两种不要在同一组件里对同一个上下文各读一次又假定一定是同一次订阅。选一种即可。

配合 Suspense 处理加载、用错误边界接住拒绝,这两点和样本的方向一致。没有边界时,拒绝会变成未接住的渲染错误。没有 Suspense 时,未完成的 Promise 没有地方显示加载。

条件调用是它和别的 Hook 的差别

对话写了三条限制:只能在组件或其它 Hook 里用,不能放进条件,必须在顶层。第一条是调用位置。后两条把它说成了和 useState 一样。use 允许出现在条件里。这是它和那些必须固定顺序的 Hook 的差别。条件成立时才 use 一个 Promise,不成立时不读,是这个 API 允许的写法。useState、useEffect 仍然不能放进条件。不要因为纠正了 use,就把别的 Hook 也放进 if。

“仍是实验”是这段对话当时的说法。生产注释不要直接抄这四个字。以项目锁定的 React 发行说明为准。版本没到包含它的那一版,调用会在编译或运行时失败,这和条件规则是两件事。先确认版本里有这个导出,再决定条件写在哪里。

别的 Hook 仍然不能放进条件

先固定 Promise,再决定写不写条件

渲染期间不要调用会返回新 Promise 的函数。把已经存在的那一份交给 use。加载交给 Suspense,拒绝交给错误边界。上下文用 use 或 useContext 其中一种。条件里可以写 use,不要写 useState。实验与否看锁定的版本,不看这段对话的原句。

组件函数每执行一次,写在函数体里的获取消息都会再跑一次。返回的是新的 Promise。use 看到的是一份还没完成的新对象,于是再次把渲染交给加载边界。用户会看到加载反复出现,即使上一次已经成功。把获取包成命名函数再在渲染时调用,次数并没有减少。应在渲染开始之前拿到同一份 Promise,或用参数做缓存键,命中时返回上一次的那份。

上下文那一行没有这个陷阱,因为上下文对象是稳定的。用 use 读或用专门的上下文函数读,选一种。两种一起读又各自存一份状态,容易改出两份样式。加载边界和错误边界要包在会挂起、会拒绝的那一层外面。没有它们,未完成和拒绝都没有落点。

对话禁止把 use 放进条件。这个 API 允许按条件调用。不需要这份数据时可以不调用。状态和效果那类 Hook 仍要无条件调用,顺序才能稳定。纠正时只放开 use,不要把状态也放进分支。实验与否是版本问题。锁定的版本没有这个导出,先升级或不要调用。有导出时,再按允许条件调用的规则来写。不要把对话里的实验二字抄进代码注释当作永久限制。

样本在组件函数里面调用获取消息,再立刻把返回值交给读取。函数体每执行一次,获取就再跑一次。 每次返回的都是一份新的、还没完成的结果。读取会因此再次把画面交给加载状态。 即使上一次已经成功,新的一份仍会让加载重新出现。这不是加载边界写错,而是等待的对象没有稳定。 对话建议把获取包进独立函数。函数若仍然在渲染时被调用,调用次数并不会下降。 应当在渲染开始之前拿到同一份,或按参数做成缓存。参数不变就返回上一次的那一份。 参数变了,才应该是另一份等待。参数没变却每次新建,加载就会按渲染次数闪动。 上下文那一条没有这个陷阱。上下文对象不会在每次渲染时变出一个新的未完成结果。 读取上下文和读取消息不要写进同一个函数。样式没有异步,不应该被加载状态挡住。 会拒绝的部分放进错误边界。样式留在边界外面。拒绝发生时,按钮的样式还在。 对话规定这个读取不能写在条件里,并且必须总在顶层,又说它仍是实验。 条件调用正是它和状态、效果那一类的差别。不需要这份数据时,可以不调用。 状态和效果仍然不能放进条件。纠正这一条时,不要把别的读取也放进分支。 实验与否要看项目锁定的版本里有没有这个导出。没有导出时,条件写法和顶层写法都会失败。 有导出之后,再按允许条件调用的规则来写。不要在升级之前就先写上。 不要把对话里的实验说明原样留在注释里。版本后来包含了它,注释仍会把人拦在旧限制上。 等待并没有消失。它交给了外层的加载边界。没有这层边界时,未完成的结果没有地方显示。 连续渲染两次若加载闪两次,获取函数就还在组件体内。把它移出之后,同样的参数不应再闪。 缓存按参数区分。参数相同复用同一份。参数不同才允许新的一份等待。 按钮样式来自上下文。上下文不变时,样式读取不应该重新进入加载。 错误边界只包住会拒绝的消息。样式在边界外,拒绝时按钮还看得到。 分支里可以不读取这份消息。分支里仍然不能调用状态和效果。这两条要同时记住。 升级版本之前不要写这个读取。升级之后再改写法。导出不存在时,怎么放都会失败。 注释若写着实验,后来的人会不敢用已经可用的导出。注释改成看锁定版本的说明。 两条样本保持两个组件。一个负责消息文本,一个负责按钮样式。合成之后样式会跟着挂起。 加载边界负责等待,错误边界负责拒绝。没有它们,未完成和失败都没有落点。 验收时用同一参数渲染两次。加载只出现一次,样式不跟着消失,才算对象已经稳定。

相关文章

分享: