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

如何在Next.js中使用React Context共享动态状态

问题原因

你猜的没错:React Context 结合 useState 存储的状态是内存级的,当页面发生服务器端导航(比如直接输入URL、跳转触发服务器渲染)或页面刷新时,整个React应用会重新初始化,内存中的状态会被清空,回到useState的初始值{}。哪怕Provider挂载在_app.js根组件上,只要组件实例重建,状态就会重置。

解决方案

方案1:通过URL传递交易ID,详情页单独获取数据(最推荐)

这是跨页面传递数据的标准实践,不依赖客户端内存状态,支持页面刷新、SEO,可靠性最高。

  1. 表格页面跳转时携带ID:
import { useRouter } from 'next/router'

const TransactionTable = () => {
  const router = useRouter()

  const handleRowClick = (transaction) => {
    // 将交易ID放入URL参数,跳转到详情页
    router.push(`/transactions/${transaction.id}`)
  }

  return (
    <table>
      {/* 表格内容,每行绑定点击事件 */}
      <tbody>
        {transactions.map(transaction => (
          <tr key={transaction.id} onClick={() => handleRowClick(transaction)}>
            <td>{transaction.id}</td>
            <td>{transaction.amount}</td>
          </tr>
        ))}
      </tbody>
    </table>
  )
}
  1. 详情页通过URLID获取数据:
    创建src/pages/transactions/[id].js页面:
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'

const TransactionDetail = () => {
  const router = useRouter()
  const { id } = router.query
  const [transaction, setTransaction] = useState(null)

  useEffect(() => {
    if (id) {
      // 调用API获取对应ID的交易详情
      fetch(`/api/transactions/${id}`)
        .then(res => res.json())
        .then(data => setTransaction(data))
    }
  }, [id])

  if (!transaction) return <div>加载中...</div>

  return (
    <div>
      <h1>交易详情:{transaction.id}</h1>
      <p>金额:{transaction.amount}</p>
      {/* 其他交易信息 */}
    </div>
  )
}

export default TransactionDetail

方案2:持久化状态到LocalStorage,保留Context数据

如果必须通过Context共享状态,可以将数据持久化到本地存储,页面刷新后自动恢复:

修改src/context/TransactionContext.js:

import { useContext, createContext, useState, useEffect } from 'react'

const TransactionContext = createContext()

export const TransactionProvider = ({ children }) => {
  // 初始化时从LocalStorage读取数据(判断window避免SSR报错)
  const [transactionData, setTransactionData] = useState(() => {
    if (typeof window !== 'undefined') {
      const savedData = localStorage.getItem('transactionData')
      return savedData ? JSON.parse(savedData) : {}
    }
    return {}
  })

  // 状态变化时同步到LocalStorage
  useEffect(() => {
    localStorage.setItem('transactionData', JSON.stringify(transactionData))
  }, [transactionData])

  return (
    <TransactionContext.Provider
      value={{ transactionData, setTransactionData }}
    >
      {children}
    </TransactionContext.Provider>
  )
}

export const useTransactionContext = () => {
  const context = useContext(TransactionContext)
  if (!context) throw new Error('Transaction context is not defined here!!')
  return context
}

注意:此方案仅适合客户端场景,存储数据不宜过大,且需考虑数据过期问题(比如用户长时间不操作,存储数据可能已失效)。

方案3:使用客户端导航保留内存状态(临时场景)

如果你的页面是纯客户端渲染,且跳转用Next.js的客户端导航(不触发服务器请求),Provider的内存状态会保留:

不要用window.location.href跳转,改用以下方式:

// 方式1:用next/link
import Link from 'next/link'
import { useTransactionContext } from 'context/TransactionContext'

const TransactionTable = () => {
  const { setTransactionData } = useTransactionContext()

  return (
    <table>
      <tbody>
        {transactions.map(transaction => (
          <tr key={transaction.id}>
            <Link href="/transaction-detail" passHref>
              <td 
                onClick={() => setTransactionData(transaction)}
                style={{ cursor: 'pointer' }}
              >
                {transaction.id}
              </td>
            </Link>
          </tr>
        ))}
      </tbody>
    </table>
  )
}
// 方式2:用useRouter
import { useRouter } from 'next/router'
import { useTransactionContext } from 'context/TransactionContext'

const TransactionTable = () => {
  const router = useRouter()
  const { setTransactionData } = useTransactionContext()

  const handleRowClick = (transaction) => {
    setTransactionData(transaction)
    router.push('/transaction-detail')
  }

  // ... 渲染表格
}

此方案局限性大:用户刷新详情页后状态会丢失,仅适合临时跳转的非关键数据场景。

内容的提问来源于stack exchange,提问作者Genaro Bonavita

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 09:55:23