const [state, set_state] = useState(1);
对比
const [state, set_state] = useState(); useEffect(() => { set_state(1); }, [])
就更新实际发生的周期而言,两者之间是否有真实的的区别?使用useEffect是否会导致额外的周期等?
useEffect
deyfvvtc1#
您可能正在寻找惰性初始状态函数参数:
惰性初始状态
initialState参数是在初始呈现期间使用的状态。在后续呈现中,将忽略该参数。如果初始状态是高开销计算的结果,则可以提供一个函数来代替,该函数将仅在初始呈现时执行:
initialState
const [state, setState] = useState(() => { const initialState = someExpensiveComputation(props); return initialState; });
但是,不只是提供一个链接,让我们检查您所展示的代码的不同行为(除了lazy initialstate函数参数之外)。下面是有关代码示例的说明:它们使用一个自定义helper钩子来记录组件呈现时间和状态值更新时间的信息,输出被序列化为JSON,因此当状态值为undefined时,它在JSON中表示为null(因为undefined不是有效的JSON类型)由于Stack Overflow的代码片段机制的限制,有很多重复的样板文件-焦点代码在App函数的主体中。
undefined
null
App
const [state, setState] = useState(1);
在这种情况下,状态初始化一次,并且从不更新。组件呈现一次:
<style>.json { background-color: hsla(0, 0%, 50%, 0.15); font-family: monospace; font-size: 1rem; padding: 0.5rem; }</style> <div id="root"></div><script src="https://cdn.jsdelivr.net/npm/react@18.2.0/umd/react.development.js"></script><script src="https://cdn.jsdelivr.net/npm/react-dom@18.2.0/umd/react-dom.development.js"></script><script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.20.12/babel.min.js"></script> <script type="text/babel" data-type="module" data-presets="env,react"> const { useCallback, useRef, useState } = React; function VisualJson ({ data }) { const json = JSON.stringify( data, // undefined doesn't serialize, so null is used as a substitute: (_key, value) => typeof value === "undefined" ? null : value, 2, ); return (<pre className="json"><code>{ json }</code></pre>); } function useComponentUpdateMeta (state) { const ref = useRef({ updates: [], get totalRenders () { return this.updates.filter(u => u.type === "render").length; }, get totalStateUpdates () { return this.updates.filter(u => u.type === "state").length; }, }); ref.current.updates.push({ type: "render", time: performance.now(), state }); const recordStateUpdate = useCallback(state => { ref.current.updates.push({ type: "state", time: performance.now(), state }); }, [ref]); return [ref.current, recordStateUpdate]; } function App () { const [state, setState] = useState(1); const [updateMeta, recordStateUpdate] = useComponentUpdateMeta(state); return (<VisualJson data={ updateMeta } />); } const reactRoot = ReactDOM.createRoot(document.getElementById("root")); reactRoot.render(<App />); </script>
const [state, setState] = useState(); useEffect(() => { setState(1); }, []);
在本例中,状态用一个隐式的undefined值初始化,组件被呈现,然后useEffect钩子的回调函数被调用,状态被更新,导致组件第二次呈现:
<style>.json { background-color: hsla(0, 0%, 50%, 0.15); font-family: monospace; font-size: 1rem; padding: 0.5rem; }</style> <div id="root"></div><script src="https://cdn.jsdelivr.net/npm/react@18.2.0/umd/react.development.js"></script><script src="https://cdn.jsdelivr.net/npm/react-dom@18.2.0/umd/react-dom.development.js"></script><script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.20.12/babel.min.js"></script> <script type="text/babel" data-type="module" data-presets="env,react"> const { useCallback, useEffect, useRef, useState } = React; function VisualJson ({ data }) { const json = JSON.stringify( data, // undefined doesn't serialize, so null is used as a substitute: (_key, value) => typeof value === "undefined" ? null : value, 2, ); return (<pre className="json"><code>{ json }</code></pre>); } function useComponentUpdateMeta (state) { const ref = useRef({ updates: [], get totalRenders () { return this.updates.filter(u => u.type === "render").length; }, get totalStateUpdates () { return this.updates.filter(u => u.type === "state").length; }, }); ref.current.updates.push({ type: "render", time: performance.now(), state }); const recordStateUpdate = useCallback(state => { ref.current.updates.push({ type: "state", time: performance.now(), state }); }, [ref]); return [ref.current, recordStateUpdate]; } function App () { const [state, setState] = useState(); const [updateMeta, recordStateUpdate] = useComponentUpdateMeta(state); useEffect(() => { setState(1); recordStateUpdate(1); }, []); return (<VisualJson data={ updateMeta } />); } const reactRoot = ReactDOM.createRoot(document.getElementById("root")); reactRoot.render(<App />); </script>
const [state, setState] = useState(() => 1);
与第一个示例类似:在这种情况下,状态被初始化一次(使用一个返回值成为初始状态值的函数),并且永远不会更新。组件被呈现一次:
<style>.json { background-color: hsla(0, 0%, 50%, 0.15); font-family: monospace; font-size: 1rem; padding: 0.5rem; }</style> <div id="root"></div><script src="https://cdn.jsdelivr.net/npm/react@18.2.0/umd/react.development.js"></script><script src="https://cdn.jsdelivr.net/npm/react-dom@18.2.0/umd/react-dom.development.js"></script><script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.20.12/babel.min.js"></script> <script type="text/babel" data-type="module" data-presets="env,react"> const { useCallback, useRef, useState } = React; function VisualJson ({ data }) { const json = JSON.stringify( data, // undefined doesn't serialize, so null is used as a substitute: (_key, value) => typeof value === "undefined" ? null : value, 2, ); return (<pre className="json"><code>{ json }</code></pre>); } function useComponentUpdateMeta (state) { const ref = useRef({ updates: [], get totalRenders () { return this.updates.filter(u => u.type === "render").length; }, get totalStateUpdates () { return this.updates.filter(u => u.type === "state").length; }, }); ref.current.updates.push({ type: "render", time: performance.now(), state }); const recordStateUpdate = useCallback(state => { ref.current.updates.push({ type: "state", time: performance.now(), state }); }, [ref]); return [ref.current, recordStateUpdate]; } function App () { const [state, setState] = useState(() => 1); const [updateMeta, recordStateUpdate] = useComponentUpdateMeta(state); return (<VisualJson data={ updateMeta } />); } const reactRoot = ReactDOM.createRoot(document.getElementById("root")); reactRoot.render(<App />); </script>
还有一点需要考虑:在开发中使用Strict Mode时,React将卸载并重新装载整个应用的节点树,从而有效地导致额外的渲染。参考文献:
<style>.json { background-color: hsla(0, 0%, 50%, 0.15); font-family: monospace; font-size: 1rem; padding: 0.5rem; }</style> <div id="root"></div><script src="https://cdn.jsdelivr.net/npm/react@18.2.0/umd/react.development.js"></script><script src="https://cdn.jsdelivr.net/npm/react-dom@18.2.0/umd/react-dom.development.js"></script><script src="https://cdn.jsdelivr.net/npm/@babel/standalone@7.20.12/babel.min.js"></script> <script type="text/babel" data-type="module" data-presets="env,react"> const { StrictMode, useCallback, useEffect, useRef, useState } = React; function VisualJson ({ data }) { const json = JSON.stringify( data, // undefined doesn't serialize, so null is used as a substitute: (_key, value) => typeof value === "undefined" ? null : value, 2, ); return (<pre className="json"><code>{ json }</code></pre>); } function useComponentUpdateMeta (state) { const ref = useRef({ updates: [], get totalRenders () { return this.updates.filter(u => u.type === "render").length; }, get totalStateUpdates () { return this.updates.filter(u => u.type === "state").length; }, }); ref.current.updates.push({ type: "render", time: performance.now(), state }); const recordStateUpdate = useCallback(state => { ref.current.updates.push({ type: "state", time: performance.now(), state }); }, [ref]); return [ref.current, recordStateUpdate]; } function App () { const [state, setState] = useState(); const [updateMeta, recordStateUpdate] = useComponentUpdateMeta(state); useEffect(() => { setState(1); recordStateUpdate(1); }, []); return (<VisualJson data={ updateMeta } />); } const reactRoot = ReactDOM.createRoot(document.getElementById("root")); reactRoot.render( <StrictMode> <App /> </StrictMode> ); </script>
1条答案
按热度按时间deyfvvtc1#
您可能正在寻找惰性初始状态函数参数:
惰性初始状态
initialState
参数是在初始呈现期间使用的状态。在后续呈现中,将忽略该参数。如果初始状态是高开销计算的结果,则可以提供一个函数来代替,该函数将仅在初始呈现时执行:但是,不只是提供一个链接,让我们检查您所展示的代码的不同行为(除了lazy initialstate函数参数之外)。
下面是有关代码示例的说明:
它们使用一个自定义helper钩子来记录组件呈现时间和状态值更新时间的信息,输出被序列化为JSON,因此当状态值为
undefined
时,它在JSON中表示为null
(因为undefined
不是有效的JSON类型)由于Stack Overflow的代码片段机制的限制,有很多重复的样板文件-焦点代码在App
函数的主体中。正在创建用值初始化的状态:
在这种情况下,状态初始化一次,并且从不更新。组件呈现一次:
创建未初始化状态,然后在
useEffect
回调中更新:在本例中,状态用一个隐式的
undefined
值初始化,组件被呈现,然后useEffect
钩子的回调函数被调用,状态被更新,导致组件第二次呈现:创建用惰性调用函数初始化的状态:
与第一个示例类似:在这种情况下,状态被初始化一次(使用一个返回值成为初始状态值的函数),并且永远不会更新。组件被呈现一次:
还有一点需要考虑:在开发中使用Strict Mode时,React将卸载并重新装载整个应用的节点树,从而有效地导致额外的渲染。
参考文献: