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

React创建Todo后无刷新添加至列表的问题排查

问题解决思路及代码修复

核心问题拆解

  1. 创建Todo后意外触发refresh_token请求,导致access_token短暂变为undefined,路由切换到未登录页面
  2. Redux中Todo列表更新逻辑错误,无法正确渲染新添加的Todo
  3. 表单提交未阻止默认行为,可能引发额外页面刷新

分步修复

1. 修复Todo创建后的列表更新逻辑

你的createTodo action里用了todoList.append(todo),这是错误的:

  • append方法会修改原数组,不符合Redux状态不可变的要求
  • append返回的是数组新长度,不是新数组,会导致todoReducer.data变成数字,无法渲染列表

修改createTodo action:

export const createTodo = (todo, token) => async (dispatch, getState) => {
  try {
    const res = await postAPI("/todo/create", todo, token);
    // 从Redux获取最新的Todo列表,避免传参过时
    const currentTodos = getState().todoReducer.data || [];
    dispatch({
      type: TODO,
      payload: {
        status: "success",
        message: "Todo创建成功",
        // 用后端返回的完整Todo对象(带自动生成的todoId)+ 原列表生成新数组
        data: [...currentTodos, res.data.todo]
      } 
    })
    dispatch({ type: ALERT, payload: { success: res.data.message } })
  } catch (error) {
    dispatch({ type: ALERT, payload: { errors: error?.response?.data.message } })
  }
};

2. 修复TodoForm的提交逻辑

  • 缺少阻止表单默认提交的代码,可能导致页面刷新
  • 不需要传todoList参数给createTodo
  • 提交后清空输入框

修改TodoForm的handleSubmit:

const handleSubmit = (e) => {
  e.preventDefault(); // 阻止表单默认提交行为
  if (!todo.text.trim()) return; // 空内容不提交
  userId && dispatch(createTodo(todo, token))
  // 清空输入框,保留userId
  setTodo({...initialState, todoUserId: userId});
}

3. 解决refresh_token触发导致的组件切换问题

在authReducer中添加isRefreshing状态,标记token刷新中的状态,避免路由误切换:

  • 首先在auth的action中添加刷新状态的处理:
// 假设你的AUTH类型action,新增SET_REFRESHING类型
export const refreshToken = () => async (dispatch) => {
  dispatch({ type: "SET_REFRESHING", payload: true });
  try {
    const res = await getAPI("/refresh_token");
    dispatch({
      type: "AUTH",
      payload: {
        access_token: res.data.access_token,
        user: res.data.user
      }
    });
  } catch (error) {
    dispatch({ type: ALERT, payload: { errors: error.response.data.message } });
  } finally {
    dispatch({ type: "SET_REFRESHING", payload: false });
  }
};
  • 修改App组件的路由判断:
<Route exact path="/" element={
  authReducer?.isRefreshing ? 
  <div>加载中...</div> : // 刷新时显示加载态,不切换页面
  (!authReducer?.access_token ? <HomepageLogout/> : <Homepage/>)
} />

4. 优化Homepage的Todo列表获取逻辑

避免每次userId变化就重复请求列表,只有当列表为空时才触发获取:

useEffect(() => {
  // 仅当userId存在且当前无Todo列表时,才请求数据
  if (userId && !todoList) {
    dispatch(getTodos(userId))
  }
}, [userId, dispatch, todoList]);

额外注意点

  • 确保你的todoReducer处理TODO类型时,是返回新对象而非修改原状态:
const initialState = { data: [] };
const todoReducer = (state = initialState, action) => {
  switch(action.type) {
    case "TODO":
      return { ...state, ...action.payload };
    default:
      return state;
  }
};
  • 检查axios拦截器逻辑,确认是否是拦截器在请求后自动触发了refresh_token(比如误判token过期)

内容的提问来源于stack exchange,提问作者Emre Kurt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 10:30:52