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

Redux Toolkit刷新后表单未同步状态问题求助

问题描述

开发简易电影网站的编辑页面,用户可修改电影详情(movie_name、movie_cast等字段),采用Redux Toolkit结合Redux Saga管理状态。页面刷新后,控制台能打印出Redux中存储的movie_name等字段的正确值,但表单输入框内的内容消失,无法正常展示电影详情。

核心原因分析

组件中用于绑定表单的本地state仅在组件初始化时从Redux读取一次值。当异步请求完成、Redux状态更新后,本地state不会自动同步最新的Redux数据,导致表单仍显示初始化时的空值。

具体来说:

  • 组件挂载时,useState(movie_name)仅以当时Redux中的初始空值作为本地state的初始值
  • 异步请求完成后,Redux中的movie_name等字段更新,但本地state未触发更新,因此表单显示为空
解决方案

方案一:监听Redux状态变化,同步更新本地state

在EditMovie组件中添加useEffect,监听Redux中电影字段的变化,一旦变化就更新对应的本地state:

import React, { useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { useParams } from 'react-router'
import Loading from '../components/Loading'
import { updateMovie, getMovieData } from "../redux/EditMovieSlice"

function EditMovie() {
    const { movie_id } = useParams()
    const dispatch = useDispatch()
    
    // 修复:添加dispatch和movie_id作为依赖,确保参数变化时重新请求
    useEffect(() => {
        dispatch(getMovieData(movie_id))
    }, [dispatch, movie_id])

    const { isLoading, movie_name, movie_image, movie_cast, movie_description, movie_favorite } = useSelector(state => state.addMovie)
    
    const [movieName, setMovieName] = useState(movie_name)
    const [movieImage, setmovieImage] = useState(movie_image)
    const [movieCast, setmovieCast] = useState(movie_cast)
    const [movieDescription, setmovieDescription] = useState(movie_description)
    const [movieFavorite, setmovieFavorite] = useState(movie_favorite)

    // 新增:监听Redux状态变化,同步更新本地state
    useEffect(() => {
        setMovieName(movie_name)
        setmovieImage(movie_image)
        setmovieCast(movie_cast)
        setmovieDescription(movie_description)
        setmovieFavorite(movie_favorite)
    }, [movie_name, movie_image, movie_cast, movie_description, movie_favorite])

    if (isLoading) {
        return <Loading />
    }

    const submitMovie = () => {
        const date = new Date()
        const month = date.getMonth() + 1
        const todayDate = `${date.getFullYear()}-${month}-${date.getDate()}` // 修复:date.getDay()是星期,应该用date.getDate()获取日期

        const movieObject = {
            movie_name: movieName,
            movie_image: movieImage,
            movie_cast: movieCast,
            movie_description: movieDescription,
            movie_favorite: movieFavorite,
            movie_create_date: todayDate,
        }

        dispatch(updateMovie(movieObject))
    }

    return (
        <div className='add-movie-container'>
            <div className='add-movie-container-form'>
                <label>Movie Name </label>
                <input type="text" value={movieName} onChange={(event) => setMovieName(event.target.value)} />
                <label>Movie Image </label>
                <input type="text" value={movieImage} onChange={(event) => setmovieImage(event.target.value)} />
                <label>Movie Cast </label>
                <input type="text" value={movieCast} onChange={(event) => setmovieCast(event.target.value)} />
                <label>Movie Description </label>
                <input type="text" value={movieDescription} onChange={(event) => setmovieDescription(event.target.value)} />
                <label>Movie Favorite </label>
                <input type="text" value={movieFavorite} onChange={(event) => setmovieFavorite(event.target.value)} />
                <button onClick={submitMovie}>Submit</button>
            </div>
        </div>
    )
}

export default EditMovie

方案二:直接绑定Redux状态,移除本地state(更符合Redux设计思路)

这种方式不需要本地state,表单直接绑定Redux中的状态,通过dispatch修改Redux字段:

1. 修改EditMovieSlice,添加更新单个字段的reducer

import { createSlice } from "@reduxjs/toolkit";

const initialState = {
    isLoading: true,
    movie_name: "",
    movie_image: "",
    movie_cast: "",
    movie_description: "",
    movie_favorite: "",
    movie_create_date: ""
}

const editMovieSlice = createSlice({
    name: "addMovie",
    initialState,
    reducers: {
        getMovieData: (state, action) => {
            state.isLoading = true
        },
        loadMovie: (state, action) => {
            state.isLoading = false
            state.movie_name = action.payload.movie_name
            state.movie_image = action.payload.movie_image
            state.movie_cast = action.payload.movie_cast
            state.movie_description = action.payload.movie_description
            state.movie_favorite = action.payload.movie_favorite
            state.movie_create_date = action.payload.movie_create_date
        },
        updateMovieField: (state, action) => {
            // 根据字段名更新对应的值
            const { field, value } = action.payload;
            state[field] = value;
        },
        updateMovie: (state, action) => {
            state.isLoading = true
        },
        updateDone: (state) => {
            state.isLoading = false
        }
    }
})

export const { setMovieData, getMovieData, updateMovie, loadMovie, updateMovieField } = editMovieSlice.actions
export default editMovieSlice.reducer

2. 修改EditMovie组件,直接使用Redux状态

import React, { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { useParams } from 'react-router'
import Loading from '../components/Loading'
import { updateMovie, getMovieData, updateMovieField } from "../redux/EditMovieSlice"

function EditMovie() {
    const { movie_id } = useParams()
    const dispatch = useDispatch()
    
    useEffect(() => {
        dispatch(getMovieData(movie_id))
    }, [dispatch, movie_id])

    const { isLoading, movie_name, movie_image, movie_cast, movie_description, movie_favorite } = useSelector(state => state.addMovie)

    if (isLoading) {
        return <Loading />
    }

    const submitMovie = () => {
        const date = new Date()
        const month = date.getMonth() + 1
        const todayDate = `${date.getFullYear()}-${month}-${date.getDate()}`

        const movieObject = {
            movie_name,
            movie_image,
            movie_cast,
            movie_description,
            movie_favorite,
            movie_create_date: todayDate,
        }

        dispatch(updateMovie(movieObject))
    }

    return (
        <div className='add-movie-container'>
            <div className='add-movie-container-form'>
                <label>Movie Name </label>
                <input 
                    type="text" 
                    value={movie_name} 
                    onChange={(e) => dispatch(updateMovieField({ field: 'movie_name', value: e.target.value }))} 
                />
                <label>Movie Image </label>
                <input 
                    type="text" 
                    value={movie_image} 
                    onChange={(e) => dispatch(updateMovieField({ field: 'movie_image', value: e.target.value }))} 
                />
                <label>Movie Cast </label>
                <input 
                    type="text" 
                    value={movie_cast} 
                    onChange={(e) => dispatch(updateMovieField({ field: 'movie_cast', value: e.target.value }))} 
                />
                <label>Movie Description </label>
                <input 
                    type="text" 
                    value={movie_description} 
                    onChange={(e) => dispatch(updateMovieField({ field: 'movie_description', value: e.target.value }))} 
                />
                <label>Movie Favorite </label>
                <input 
                    type="text" 
                    value={movie_favorite} 
                    onChange={(e) => dispatch(updateMovieField({ field: 'movie_favorite', value: e.target.value }))} 
                />
                <button onClick={submitMovie}>Submit</button>
            </div>
        </div>
    )
}

export default EditMovie

额外修复点

  • 原代码中date.getDay()获取的是星期数,改为date.getDate()获取当月日期,避免生成错误的日期格式
  • 原useEffect的依赖数组为空,添加dispatch和movie_id确保参数变化时重新请求数据

内容的提问来源于stack exchange,提问作者Aditya Dixit

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 17:02:25