You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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。

第二步:修改表单组件代码

需要做三处调整:

  1. 组件接收setCanvas prop,删除内部的const [canvas, setCanvas] = useState()定义
  2. 修复状态异步更新bug:你之前调用setTrack(data)后立即用track传给Canvas,此时track还是旧值,直接用接口返回的data即可
  3. 新增空数据判断,展示要求的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 16:18:01