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

React Redux添加好友功能报错:friends.find/map不是函数求助

解决添加好友功能中的TypeError: friends.find/map is not a function错误

问题场景

开发添加好友功能时,点击「添加好友」按钮触发错误:TypeError: friends.find is not a function。在Friend.jsx中添加一段标记为Error的代码后,错误变为friends.map is not a function(错误出现在friendsList.jsx组件)。

相关代码

Friend.jsx组件

import { PersonAddOutlined, PersonRemoveOutlined } from "@mui/icons-material";
import { 
    Box,
    Divider,
    IconButton,
    Typography,
    useTheme
} from "@mui/material";
import { useDispatch, useSelector } from "react-redux";
import { setFriends } from "state";
import FlexBetween from "./FlexBetween";
import UserImage from "./UserImage";
import { useNavigate } from "react-router-dom";

const Friend = ({ friendId, name, subtitle, userPicturePath }) => {
    const dispatch = useDispatch();
    const navigate = useNavigate();
    const { _id } = useSelector((state) => state.user);
    const token = useSelector((state) => state.token);
    const friends = useSelector((state) => state.user.friends);

    // if (!Array.isArray(friends)) {     |
    //     return console.log(friends);   |<=== Error
    // }                                  |

    // eslint-disable-next-line react-hooks/rules-of-hooks
    const { palette } = useTheme();
    const primaryLight = palette.primary.light;
    const primaryDark = palette.primary.dark;
    const main = palette.neutral.main;
    const medium = palette.neutral.medium;
    

    const isFriend = friends.find((friend) => friend._id === friendId);
    
    const patchFriend = async() => {
        const response = await fetch(
            `http://localhost:3001/users/${_id}/${friendId}`,
            {
                method: "PATCH",
                headers: {
                    Authorization: `Bearer ${token}`,
                    "Content-Type": "application/json"
                },
            }
        );
        const data = await response.json();
        dispatch(setFriends({ friends: data }));
        // console.log("array123: ",Array.isArray(friends))
        // console.log("array123: ")

    };

    return (
        <FlexBetween>
            <FlexBetween gap="1rem">
                <UserImage image={userPicturePath} size="55px" />
                <Box
                onClick={() => {
                    navigate(`/profile/${friendId}`);
                    navigate(0); 
                }}
                >
                    <Typography
                    color={main}
                    variant="h5"
                    fontWeight="500"
                    sx={{
                        "&:hover": {
                            color: palette.primary.light,
                            cursor: "pointer"
                        }
                    }}
                    >
                        {name}
                    </Typography>
                    <Typography color={medium} fontSize="0.75rem">
                        {subtitle}
                    </Typography>
                </Box>
            </FlexBetween>
            <IconButton
            onClick={() => patchFriend()}
            sx={{ backgroundColor: primaryLight, p: "0.6rem" }}
            >
                {isFriend ? (
                    <PersonRemoveOutlined sx={{ color: primaryDark }} />
                ) : (
                    <PersonAddOutlined sx={{ color: primaryDark }} />
                )}
            </IconButton>
        </FlexBetween>
    )
};

export default Friend;

state.js代码

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

const initialState = {
    mode: "light",
    user: null,
    token: null,
    posts: [],
};

export const authSlice = createSlice({
    name: "auth",
    initialState,
    reducers: {
        setLogin: (state, action) => {
            state.user = action.payload.user;
            state.token = action.payload.token;
        },
        setLogout: (state) => {
            state.user = null;
            state.token = null;
        },
        setFriends: (state, action) => {
            if (state.user) {
                state.user.friends = action.payload.friends;
            } else {
                console.error("user friends is not exist")
            }
        },
        setPosts: (state, action) => {
            state.posts = action.payload.posts;
        },
        setPost: (state, action) => {
            const updatedPosts = state.posts.map((post) => {
                if (post._id === action.payload.post._id) return action.payload.post;
                return post;
            });
            state.posts = updatedPosts;
        },
    },
});

export const { setLogin, setLogout, setFriends, setPosts, setPost } = authSlice.actions;
export default authSlice.reducer;

问题原因

核心问题是**friends变量并非数组类型**,导致无法调用数组方法find和map,具体诱因:

  1. Redux初始状态中state.user为null,state.user.friends未被初始化为数组;若登录后后端返回的用户数据中friends字段不是数组,也会引发异常。
  2. PATCH请求后直接将后端返回的data赋值给state.user.friends,若后端返回的data结构不是数组(比如是包含friends的对象),会导致friends变为非数组类型。
  3. 注释中的Error代码块违反React Hooks规则(在useTheme调用前提前返回),引发组件渲染异常。

解决方案

1. 初始化Redux状态为数组

修改state.js的initialState,确保user默认包含空数组的friends:

const initialState = {
    mode: "light",
    user: { friends: [] }, // 替换null为包含空friends数组的对象
    token: null,
    posts: [],
};

或者在setLogin时补全friends数组:

setLogin: (state, action) => {
    state.user = { ...action.payload.user, friends: action.payload.user.friends || [] };
    state.token = action.payload.token;
},

2. 校验后端返回数据格式

检查PATCH接口的返回结构,若后端返回的是{ friends: [...] }格式的对象,修改patchFriend中的dispatch逻辑:

const data = await response.json();
dispatch(setFriends({ friends: data.friends })); // 取data中的friends数组,而非直接传data

3. 组件中添加默认值保障

在获取friends时添加可选链和默认值,避免null/undefined:

const friends = useSelector((state) => state.user?.friends || []);

4. 移除违规的Error代码块

删除Friend.jsx中那段注释的Error代码,它违反了React Hooks的调用顺序规则(必须在组件顶层按顺序调用,不能在条件判断后提前返回)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 09:55:59