Next.js中React组件未同步state变量值问题求助
Next.js中React组件状态同步异常问题排查与解决
父组件维护了topXplain状态,修改该状态时页面上的YES/NO文本能正常切换,但第三个传入动态值tpXpln={topXplain}的ReviewSession子组件始终保持初始的true状态,无法同步父组件的状态变化。前两个传入固定值的子组件显示正常。
父组件相关代码
..... const [topXplain, setTopXplain] = useState(true); ..... <div className="z-10 max-w-5xl w-full ... text-sm lg:flex"> <div className="flex flex-col"> <div>{topXplain ? "YES" : "NO"}</div> <ReviewSession userID={user!.uid} lang={prefLang} revType={revisType} tpXpln={true} tpXplFn={updateUserTopXplain} /> <ReviewSession userID={user!.uid} lang={prefLang} revType={revisType} tpXpln={false} tpXplFn={updateUserTopXplain} /> <ReviewSession userID={user!.uid} lang={prefLang} revType={revisType} tpXpln={topXplain} tpXplFn={updateUserTopXplain} /> </div> </div>
ReviewSession子组件相关代码
'use client'; import { useState, useEffect } from 'react'; ..... var utl = require('../../Utils.tsx'); export default function ReviewSession({ userID, lang, revType, tpXpln, tpXplFn }: { userID: string, lang: string, revType: string, tpXpln: boolean, tpXplFn: (v: boolean) => void }) { ..... const [showTopXpln, setShowTopXpln] = useState(tpXpln); ..... function checkClick() { tpXplFn(!showTopXpln) setShowTopXpln(!showTopXpln); } /* End of checkClick */ return ( <div className="flex flex-col items-center"> {sessionReady && <> {showTopXpln && <div className="bg-amber-900 text-slate-100 text-2xl font-serif p-3 my-3"> {utl.topExplain(lang)} </div> } <div className='flex justify-start items-center bg-amber-700 p-3 my-1'> <input type={"checkbox"} checked={showTopXpln} onChange={() => checkClick()} className="bg-cyan-200" /> <label className='text-slate-100 text-base font-serif ml-4'> {showTopXpln ? utl.noTopExplain(lang) : utl.needTopExplain(lang)} </label> </div> ..... </> } ..... </div> ); }
问题原因
子组件ReviewSession内部通过useState(tpXpln)初始化了本地状态showTopXpln,但React的useState初始值仅在组件首次挂载时生效。当父组件的topXplain状态变化导致传入子组件的tpXpln props更新时,子组件的本地状态showTopXpln不会自动同步更新,因此始终保持首次挂载时的初始值(true)。
前两个子组件传入的是固定布尔值,props不会变化,所以不存在同步问题;第三个子组件的props随父组件状态动态变化,就暴露了这个问题。
解决方法
方法一:使用useEffect监听props变化,同步本地状态
在子组件中添加useEffect,监听tpXpln的变化,一旦props更新就同步更新本地状态:
export default function ReviewSession({ userID, lang, revType, tpXpln, tpXplFn }: { userID: string, lang: string, revType: string, tpXpln: boolean, tpXplFn: (v: boolean) => void }) { ..... const [showTopXpln, setShowTopXpln] = useState(tpXpln); // 监听tpXpln变化,同步本地状态 useEffect(() => { setShowTopXpln(tpXpln); }, [tpXpln]); ..... }
方法二:直接使用props作为状态(去掉本地state)
如果子组件的状态不需要独立于父组件维护,可以直接使用传入的tpXpln props,同时修改点击逻辑直接更新父组件状态:
export default function ReviewSession({ userID, lang, revType, tpXpln, tpXplFn }: { userID: string, lang: string, revType: string, tpXpln: boolean, tpXplFn: (v: boolean) => void }) { ..... // 移除本地state,直接使用tpXpln function checkClick() { tpXplFn(!tpXpln); } /* End of checkClick */ return ( <div className="flex flex-col items-center"> {sessionReady && <> {tpXpln && <div className="bg-amber-900 text-slate-100 text-2xl font-serif p-3 my-3"> {utl.topExplain(lang)} </div> } <div className='flex justify-start items-center bg-amber-700 p-3 my-1'> <input type={"checkbox"} checked={tpXpln} onChange={() => checkClick()} className="bg-cyan-200" /> <label className='text-slate-100 text-base font-serif ml-4'> {tpXpln ? utl.noTopExplain(lang) : utl.needTopExplain(lang)} </label> </div> ..... </> } ..... </div> ); }
注:方法二更适合状态完全由父组件控制的场景,避免本地状态与props的同步问题;方法一则保留子组件本地状态,适合需要临时独立维护状态的场景。
内容的提问来源于stack exchange,提问作者Michel
相关产品推荐
相关产品推荐

