作者回复: 你好,学习前端-react,抱歉这几天在赶稿回复晚了。 你说得对。useEffect的副作用回调和清除函数,它们都在提交阶段执行,且大多情况都是异步执行的。这些函数被加入callback更新队列。在真实DOM绘制之后,下一次React渲染之前,这个队列里的callback会依次执行,所以这时候callback能拿到真实DOM。 这张图在第一次画时,只画了同步执行的情况,给大家造成了误解,还请见谅。目前图片已经做了更新,依然省略了一些实现细节,但更贴近实际情况了,请以这一版为准。
作者回复: 你好,船长,从实现功能来讲你用useState+useEffect代替useMemo是可行的。正如你说的,确实多了一次渲染。具体来说,useMemo的回调是在渲染过程中执行,而useEffect的回调会在提交阶段执行,useEffect回调内部调用了useState的话,会触发一次新的渲染。从用户感知上应该没太大差别,毕竟渲染过程是异步的,useEffect的回调也是异步的。 在实际项目中,我们可能会遇到连续在一个组件中写十来个Hooks的情况,每当存在这种跨多次渲染还相关的Hooks,都会多少增加一些调试的难度。
作者回复: 你好,满眼星辰,抱歉这几天在赶稿回复晚了。 你说得对。useEffect记录的副作用回调和清除函数,都在提交阶段执行,且大多情况都是异步执行的。这些函数被加入callback更新队列。在真实DOM绘制之后,下一次React渲染之前,队列里的callback会依次执行。 在第一次画图例时,只画了同步执行的情况,给你造成了误解,还请见谅。目前图片已经做了更新,依然省略了一些实现细节,但更贴近实际情况了,请以这一版为准。
作者回复: 你好,都市夜归人,这两周我都在赶稿,抱歉回复晚了。这里所指的“回调函数”,对于: const memoized = useMemo(() => createByHeavyComputing(a, b), [a, b]); 指的是其中的() => createByHeavyComputing(a, b),同时也叫工厂函数; 对于 const memoizedFunc = useCallback(() => {if (a) b()}, [a, b]); 指的是() => {if (a) b()}; () => createByHeavyComputing(a, b) 和 () => {if (a) b()} 如果符合执行条件的话,会在渲染阶段执行。 对于 useEffect(() => { if (province === '山东') { setCities(['济南', '青岛', '淄博']); }}, [province]); 指的是 () => { if (province === '山东') { setCities(['济南', '青岛', '淄博']); }} 如果符合执行条件的话,() => { if (province === '山东') { setCities(['济南', '青岛', '淄博']); }} 会在提交阶段执行。
作者回复: 你好,都市夜归人,抱歉这两周在赶稿回复晚了。这里说的是useEffect的两个参数。 const KanbanCard = ({ title, status }) => { const [displayTime, setDisplayTime] = useState(status); 这段代码只是为了提示一下useEffect所在的相对位置。 下面的: useEffect(() => { // ... return function cleanup() { // ... }; }, [status]); 中的: () => { // ... return function cleanup() { // ... }; } 就是useEffect第一个参数,称作副作用回调函数(Effect Callback); 而后面的: [status] 就是第二个参数,称作依赖值数组(Dependencies)。