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

React视频应用点赞后页面消失报错,刷新点赞数增加问题求助

React视频应用点赞崩溃问题分析与解决

我正在开发一个基于JSON Server的视频应用,其他功能正常,但点击点赞/取消点赞按钮时页面崩溃,抛出Objects are not valid as react child错误,刷新页面后点赞数能正常更新。以下是问题根源和修复方案:


相关代码片段

状态切片代码

import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"
import { getVideo, updateReaction } from "./videoApi"

const initialState = {
    video: {},
    loading: false,
    isError: false, 
    error: ''
}

export const fetchVideo = createAsyncThunk('vidoes/fetchVideo', async (id) => {
    const videos = await getVideo(id);
    return videos;
});

export const fetchReact = createAsyncThunk('video/reaction', async ({ id, reaction }) => {
    const videoReaction = await updateReaction({ id, reaction })
    return videoReaction;
})

const videoSlice = createSlice({
    name: 'video',
    initialState,
    extraReducers: (builder) => {
        builder.addCase(fetchVideo.pending, (state) => {
            state.loading = true;
            state.isError = false;
        })

        builder.addCase(fetchVideo.fulfilled, (state, action) => {
            state.loading = false;
            state.video= action.payload;
        })

        builder.addCase(fetchVideo.rejected, (state, action) => {
            state.loading = false;
            state.isError = true;
            state.error = action.error?.message;
            state.video = [];
        })

        builder.addCase(fetchReact.pending, (state) => {
            return state;
        })

        builder.addCase(fetchReact.fulfilled, (state, action) => {
            state.video.likes = action.payload;
            state.video.unlikes = action.payload;
        })

        builder.addCase(fetchReact.rejected, (state) => {
            return state;
        })

    }
});

export default videoSlice.reducer;

Video API代码

import axios from '../../utils/axios'

export const getVideo = async (id) => {
  const response = await axios.get(`/videos/${id}`)
  return response.data;
}

export const updateReaction = async ({ id, reaction }) => {
  console.log(id)
  const { data } = await axios.get(`/videos/${id}`)
  if (data) {
    let updatedReaction =
      reaction === 'like'
        ? {
          likes: data.likes + 1,
        }
        : {
          unlikes: data.unlikes + 1,
        };

    const response = await axios.patch(`/videos/${id}`, updatedReaction);
    return response.data;
  }
}

点赞组件代码

import React from 'react';
import { useDispatch } from 'react-redux';
import LikeImg from '../../assets/like.svg';
import UnLikeImg from '../../assets/unlike.svg'
import { fetchReact } from '../../features/video/video_slice';

const LIke = ({ likes, unlikes, id }) => {
    console.log(id)
    const dispatch = useDispatch();

    const reactionHandler = ({ id, reaction }) => {
        dispatch(fetchReact({ id, reaction }))
    }

    return (
        <div className="flex gap-10 w-48">
            <div className="flex gap-1">
                <div
                    className="shrink-0 cursor-pointer"
                    onClick={() => reactionHandler({ id, reaction: 'like' })}
                >
                    <img className="w-5 block" src={LikeImg} alt="Like" />
                </div>
                <div className="text-sm leading-[1.7142857] text-slate-600">
                    {likes >= 1000 ? `${ likes }K` : likes}
                </div>
            </div>
            <div className="flex gap-1">
                <div
                    onClick={() => reactionHandler({ id, reaction: 'unlike' })}
                    className="shrink-0 cursor-pointer"
                >
                    <img className="w-5 block" src={UnLikeImg} alt="Unlike" />
                </div>
                <div className="text-sm leading-[1.7142857] text-slate-600">
                    {unlikes >= 1000 ? `${ unlikes }K` : unlikes}
                </div>
            </div>
        </div>
    );
};

export default LIke;

问题根源

1. Redux状态更新逻辑错误

在fetchReact.fulfilled的reducer中,action.payload是API返回的完整视频对象(包含所有字段的JSON数据),但代码错误地将整个对象赋值给了likes和unlikes:

state.video.likes = action.payload;
state.video.unlikes = action.payload;

这导致likes和unlikes从数字变成了对象。

2. 组件渲染时尝试渲染对象

在点赞组件中,代码直接渲染likes和unlikes的值:

{likes >= 1000 ? `${ likes }K` : likes}

当likes是对象时,React无法渲染对象类型的子元素,直接抛出Objects are not valid as react child错误,导致页面崩溃。

额外问题

  • 无论点赞还是取消点赞,都会同时覆盖likes和unlikes,导致非目标计数被错误更新
  • 视频根页面存在重复的渲染判断,会导致正确内容被错误覆盖

修复方案

1. 修正Redux状态更新逻辑

直接用API返回的完整视频对象替换state中的video,保证所有字段类型正确:

builder.addCase(fetchReact.fulfilled, (state, action) => {
    state.video = action.payload;
})

或者只更新需要的字段(更高效,但需要确保字段对应):

builder.addCase(fetchReact.fulfilled, (state, action) => {
    state.video.likes = action.payload.likes;
    state.video.unlikes = action.payload.unlikes;
})

2. 修复视频根页面的渲染逻辑

删除重复的错误判断,保留正确的内容渲染分支:

// 删掉这段重复且错误的判断
// if (!loading && !isError && video?.id) {
//     content = <div className="col-span-12"><srong>{error}</srong></div>
// }

3. 可选:优化错误处理

在fetchReact.rejected中添加错误状态更新,方便后续处理错误提示:

builder.addCase(fetchReact.rejected, (state, action) => {
    state.isError = true;
    state.error = action.error?.message;
})

验证效果

修改完成后,点击点赞/取消点赞按钮时,likes和unlikes会保持数字类型,组件能正常渲染数值,页面不再崩溃,同时点赞数会实时更新,无需刷新页面。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 07:40:36