You need to enable JavaScript to run this app. React setState hook无法设置值:点击触发setClickedMovieId后仍返回默认值
优惠活动
大模型
产品
解决方案
定价
更多

React setState hook无法设置值:点击触发setClickedMovieId后仍返回默认值

问题根因

有两个核心问题导致当前现象:

  • 你把状态更新按钮放在了<NavLink>组件内部,点击按钮时事件会向上冒泡触发<NavLink>的跳转行为,而React的setState是异步更新的,跳转触发时状态还未完成更新,因此读取到的clickedMovieId始终是旧值0。
  • 从逻辑设计上你完全不需要用全局状态存储点击的电影id,每个遍历出来的电影条目本身就持有唯一id,额外用状态拼接路由属于冗余逻辑,反而容易引发问题。你观察到的控制台始终输出0,也是因为状态还没更新完成页面就已经跳转,组件卸载后监听逻辑不会再执行。

修复方案

方案1:精简逻辑(更推荐)

直接删除冗余的clickedMovieId状态和对应的监听useEffect,给每个电影的<NavLink>直接绑定当前条目的id即可,代码修改后如下:

const MovieCards = () =>  {
  const { movies } = useContext(MoviesContext);  

  return (
    <div >
      <Grid container spacing={1}>
      {movies.map((movie) => (
        <Grid item xs={6} sm={2} key={movie.id}>
          {/* 直接用当前遍历到的movie.id拼接路径,不需要额外状态 */}
          <NavLink to={`movie/${movie.id}`}>
            <Card className="card">
              <CardActionArea>
                <CardMedia
                  component="img"
                />
              </CardActionArea>
              <CardActions>
                <Button size="small" color="primary">
                  <FavoriteBorderIcon />
                </Button>
                <Button size="small" color="primary">
                  {movie.rating}
                </Button>
              </CardActions>
            </Card>
          </NavLink>
        </Grid>
      ))}
      </Grid>
    </div>
  );
}

export default MovieCards;

方案2:如果确实需要保留clickedMovieId状态做其他逻辑

你需要阻止按钮点击事件冒泡到上层的<NavLink>,同时在状态更新完成后再手动触发跳转,不要用<NavLink>的默认跳转行为:

  1. 先从react-router-dom引入useNavigate钩子
  2. 移除包裹Card的<NavLink>组件
  3. 按钮点击事件中先更新状态,再手动跳转
    修改后代码示例:
import { useNavigate } from 'react-router-dom';

const MovieCards = () =>  {
  const { movies } = useContext(MoviesContext);  
  const navigate = useNavigate();
  const [clickedMovieId, setClickedMovieId] = useState<number>(0);

  useEffect(() => {
    console.log('Current value of movie id state', clickedMovieId);
    // 状态更新完成后再跳转
    if (clickedMovieId !== 0) {
      navigate(`movie/${clickedMovieId}`);
    }
  }, [clickedMovieId, navigate]);

  const handleMovieClick = (e, id) => {
    e.stopPropagation();
    setClickedMovieId(id);
  }

return (
    <div >
      <Grid container spacing={1}>
      {movies.map((movie) => (
        <Grid item xs={6} sm={2} key={movie.id}>
          <Card className="card">
            <CardActionArea>
              <CardMedia
                component="img"
              />
            </CardActionArea>
            <CardActions>
              <Button size="small" color="primary">
                <FavoriteBorderIcon />
              </Button>
              <Button size="small" color="primary" onClick={(e) => handleMovieClick(e, movie.id)}>
                {movie.rating}
              </Button>
            </CardActions>
          </Card>
        </Grid>
      ))}
      </Grid>
    </div>
  );
}

export default MovieCards;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 14:48:04