Next.js表单提交后更新Index页面 侧边栏表单数据传递方案咨询
解决方法
你遇到的是同层级组件之间的状态同步问题,表单组件Controls和Index页面都在Layout下渲染,属于平级组件,状态默认无法互通。你之前把canvas状态维护在表单组件内部,Index页面自然拿不到最新值,用状态提升或者Context就能解决。
方案1:状态提升(小项目首选,无需额外依赖)
把共享状态canvas移到公共父层(也就是Index页面)维护,再将状态更新函数作为prop传给表单组件即可。
第一步:修改Index页面代码
import { useState } from 'react' import Layout from '../components/layout' import Controls from '../components/controls' import Aside from '../components/aside' export default function Index() { // 将canvas状态移到Index页面维护 const [canvas, setCanvas] = useState(null) return ( <Layout> <section>Hello: {canvas}</section> {/* 把状态更新方法作为prop传给表单组件 */} <Controls setCanvas={setCanvas} /> <Aside /> </Layout> ) }
如果你一定要保留getLayout写法,可以用下面的方案2。
第二步:修改表单组件代码
需要做三处调整:
- 组件接收
setCanvasprop,删除内部的const [canvas, setCanvas] = useState()定义 - 修复状态异步更新bug:你之前调用
setTrack(data)后立即用track传给Canvas,此时track还是旧值,直接用接口返回的data即可 - 新增空数据判断,展示要求的
no data available提示
修改后的核心逻辑(handleSubmit部分):
// 组件头部接收prop export default function FormControls({ setCanvas }) { // ...其余原有代码不变 const handleSubmit = async (event) => { event.preventDefault() const radioSelected = { refreshRate } console.log(radioSelected) const RefreshRateSelected = JSON.stringify(radioSelected, null, 4) const beginDate = epoch(startDate) const rightThisSecond = Math.round(Date.now() / 1000) const res = await fetch( `/api/tracks/timeseries/${beginDate}/${rightThisSecond}` ) const datePicker = { startTime: beginDate, endTime: rightThisSecond, } const data = await res.json() console.log(data) // 校验未选刷新频率 if (radioSelected.refreshRate === undefined) { console.log('select a radio') return setCanvas(<h2>Make sure you select a refresh rate!</h2>) } // 校验接口返回错误 if (data.error) { return setCanvas(<h2>{data.error}</h2>) } // 校验空数据 if (!data || data.length === 0) { return setCanvas(<h2>no data available</h2>) } // 正常返回数据逻辑 data.unshift(JSON.parse(RefreshRateSelected)) data.unshift(datePicker) setTrack(data) // 直接用新拿到的data传参,不要用旧的track变量 setCanvas(<Canvas data={data} />) } // ...其余原有代码不变 }
方案2:React Context(适合层级深的大项目,无需层层传prop)
如果你的项目组件嵌套深,传prop麻烦,可以用Context做全局状态共享。
1. 新建Context文件 contexts/CanvasContext.js
import { createContext, useContext, useState } from 'react' const CanvasContext = createContext() export function CanvasProvider({ children }) { const [canvas, setCanvas] = useState(null) return ( <CanvasContext.Provider value={{ canvas, setCanvas }}> {children} </CanvasContext.Provider> ) } export function useCanvas() { return useContext(CanvasContext) }
2. 全局包裹Provider
在你的根布局(Layout组件或_app.js)里用CanvasProvider包裹所有子组件:
import { CanvasProvider } from '../contexts/CanvasContext' export default function Layout({ children }) { return ( <CanvasProvider> {/* 原有布局代码 */} {children} </CanvasProvider> ) }
3. Index页面读取状态
import { useCanvas } from '../contexts/CanvasContext' import Layout from '../components/layout' import Controls from '../components/controls' import Aside from '../components/aside' export default function Index() { const { canvas } = useCanvas() return <section>Hello: {canvas}</section> } Index.getLayout = function getLayout(page) { return ( <Layout> {page} <Controls /> <Aside /> </Layout> ) }
4. 表单组件调用更新方法
import { useCanvas } from '../contexts/CanvasContext' export default function FormControls() { const { setCanvas } = useCanvas() // 其余代码和方案1里的表单逻辑完全一致,handleSubmit里直接用setCanvas即可 }
内容的提问来源于stack exchange,提问作者rf guy
相关产品推荐
相关产品推荐

