React/Nextjs 上下文提供程序状态在第一次加载/刷新时无法访问,但在状态更改时工作正常

Posted

技术标签:

【中文标题】React/Nextjs 上下文提供程序状态在第一次加载/刷新时无法访问,但在状态更改时工作正常【英文标题】:React/Nextjs context provider state not accessible on first load / refresh, but works fine when state changes 【发布时间】:2021-11-18 07:22:49 【问题描述】:

我正在学习反应,我正在使用上下文 API 构建状态管理。我的上下文是这样的:

//TodoContext.js
const todos = [];
const totalTodos = () => ;
const getTodos = () => ;
const saveTodos = () => ;
export const TodoContext = createContext(todos, totalTodos, getTodos, saveTodos )

通过自定义钩子我做到了。

//useTodos.js
export default function useTodos()
  const [todos, setTodos] = useState([]); //added in an attempt to trigger change on value update
  const totalTodos = () => 
     return todos.length;
  
  const getTodos = () => 
    let todoList = [];
    if (typeof window !== 'undefined') 
        todoList = JSON.parse(localStorage.getItem('todos'));
    
    return todoList;
  
  const saveTodos = (todos) => 
   //saves to local storage, then:
   setTodos(todos)
  
 return  todos, totalTodos, getTodos, saveTodos  

在我的布局文件中:

const  todos, totalTodos, getTodos  = useTodos();
...
return (
   <TodosContext.Provider value= todos, totalTodos, getTodos, saveTodos >
     <div>Todo count: totalTodos()</div>
     children
   </TodosContext.Provider>
)

我的问题是当我第一次加载页面或导航到使用相同布局的另一个页面时,totalTodos 没有显示。但是,例如,如果使用saveTodos 方法保存一个新的待办事项,totalTodos 开始显示正确的值,然后一切看起来都正常。我究竟做错了什么?我有不同的想法,比如使用 memo 和 useRef 等,但我无法解决这个问题。任何帮助表示赞赏。

【问题讨论】:

你可以试试todos.length 代替totalTodos 吗? @ChemiAdel 谢谢,但效果相同。 【参考方案1】:

你需要添加useEffect来初始化钩子调用后的状态

useTodos.js

import useState, useEffect from 'react'
    
...code    
    
//useEffect helps to update states once when client-side ready (only with [])
useEffect(() => 
    
todoList = localStorage.getItem('todos');
    
setTodos(todoList)
    
,[]); <--- client-side only

【讨论】:

我之前实际上已经尝试过,这给出了正确的负载值,但反应性丢失了;当我改变状态时,计数不会更新。 尝试用todos.length 代替totalTodos()useEffect【参考方案2】:

我已经设法使用这种方法解决了这个问题(重构代码以获取在其他地方找到的 api 结果):

在布局文件中: const [todosCount, setTodosCount] = useState(0)

const getCount = () => 
  setTodosCount( totalTodos() )
  return () =>  

useEffect( ()=>
  getCount()
)

巧合的是,这似乎也有效:

useEffect( ()=>
  setTodosCount( totalTodos() )
, [()=>]); //passing an empty function

不用说,我不知道发生了什么,但它确实有效。一旦我找到有关正在发生的事情的更多信息或任何有经验的人的解释,将更新答案。

【讨论】:

以上是关于React/Nextjs 上下文提供程序状态在第一次加载/刷新时无法访问,但在状态更改时工作正常的主要内容,如果未能解决你的问题,请参考以下文章

React/nextJS:如何调试 s-s-r react 应用的不同节点?

React NextJS Firebase 错误刷新名为“[DEFAULT]”的 Firebase 应用程序已存在

从零搭建一个基于React+Nextjs的SSR网站:如何搭建服务器并部署Nextjs项目

React + NextJS - 受保护的路线

无法读取上下文提供程序中的 useReducer 挂钩更新的状态

React/NextJS 使用 UseEffect 错误:渲染的钩子比上一次渲染期间更多