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

React创建分组后无法显示更新值的技术问题求助

React编辑作者/位置后新值不显示问题解决

问题描述

正在进行React练习:读取本地JSON数据,通过useState管理并展示,实现点击编辑作者和位置字段后保存的功能。

  • 问题:保存作者或位置的更新值后,新值不会显示,反而被清除,但下拉菜单筛选全选时能看到新值。
  • 需求:用户更新作者或位置后,新值能正常展示。

核心组件代码(Authorsgroup.jsx)

import { useEffect, useState } from "react";
import {
  Container,
  Accordion,
  AccordionSummary,
  AccordionDetails,
  Typography,
  Button
} from "@mui/material";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import EditIcon from "@mui/icons-material/Edit";

const Authorsgroup = ({
  posts,
  groupDropdownValue,
  setShowForm,
  setPostId,
  showForm
}) => {
  const authorGroup = posts.reduce((group, authorgroup) => {
    (group[authorgroup.author.replace(/ +/g, "")] =
      group[authorgroup.author.replace(/ +/g, "")] || []).push(authorgroup);
    return group;
  }, {});

  const [authorGroupValues, setAuthorGroupValues] = useState(authorGroup);

  useEffect(() => {
    setAuthorGroupValues(authorGroup);
    console.log(authorGroupValues);
  }, [groupDropdownValue, showForm]);

  return (
    <>
      <Container>
        {/* show group of Tapesh */}
        <Container style={{ marginTop: "3rem" }}>
          {authorGroupValues?.Tapesh.map((post, index) => (
            <Accordion key={index}>
              <AccordionSummary
                expandIcon={<ExpandMoreIcon />}
                aria-controls="panel1a-content"
                id="panel1a-header"
              >
                <Typography variant="h6" style={{ color: "#EB1283" }}>
                  {post.id} {post.author} {post.location}
                </Typography>
              </AccordionSummary>
              <AccordionDetails>
                <Typography variant="h4">{post.location}</Typography>
                <Typography>{post.text}</Typography>
                <Button
                  variant="outlined"
                  onClick={() => {
                    setShowForm(!showForm);
                    setPostId(post.id);
                  }}
                  startIcon={<EditIcon />}
                >
                  Edit
                </Button>
              </AccordionDetails>
            </Accordion>
          ))}
        </Container>

        {/* show group of HappyManager */}
        <Container style={{ marginTop: "3rem" }}>
          {authorGroupValues?.HappyManager.map((post, index) => (
            <Accordion key={index}>
              <AccordionSummary
                expandIcon={<ExpandMoreIcon />}
                aria-controls="panel1a-content"
                id="panel1a-header"
              >
                <Typography variant="h6" style={{ color: "orange" }}>
                  {post.id} {post.author} {post.location}
                </Typography>
              </AccordionSummary>
              <AccordionDetails>
                <Typography variant="h4">{post.location}</Typography>
                <Typography>{post.text}</Typography>
                <Button
                  variant="outlined"
                  onClick={() => {
                    setShowForm(!showForm);
                    setPostId(post.id);
                  }}
                  startIcon={<EditIcon />}
                >
                  Edit
                </Button>
              </AccordionDetails>
            </Accordion>
          ))}
        </Container>

        {/* show group of HappyDeveloper */}
        <Container style={{ marginTop: "3rem" }}>
          {authorGroupValues?.HappyDeveloper.map((post, index) => (
            <Accordion key={index}>
              <AccordionSummary
                expandIcon={<ExpandMoreIcon />}
                aria-controls="panel1a-content"
                id="panel1a-header"
              >
                <Typography variant="h6" style={{ color: "green" }}>
                  {post.id} {post.author} {post.location}
                </Typography>
              </AccordionSummary>
              <AccordionDetails>
                <Typography variant="h4">{post.location}</Typography>
                <Typography>{post.text}</Typography>
                <Button
                  variant="outlined"
                  onClick={() => {
                    setShowForm(!showForm);
                    setPostId(post.id);
                  }}
                  startIcon={<EditIcon />}
                >
                  Edit
                </Button>
              </AccordionDetails>
            </Accordion>
          ))}
        </Container>

        {/* show group of HappyUser */}
        <Container style={{ marginTop: "3rem" }}>
          {authorGroupValues?.HappyUser.map((post, index) => (
            <Accordion key={index}>
              <AccordionSummary
                expandIcon={<ExpandMoreIcon />}
                aria-controls="panel1a-content"
                id="panel1a-header"
              >
                <Typography variant="h6" style={{ color: "red" }}>
                  {post.id} {post.author} {post.location}
                </Typography>
              </AccordionSummary>
              <AccordionDetails>
                <Typography variant="h4">{post.location}</Typography>
                <Typography>{post.text}</Typography>
                <Button
                  variant="outlined"
                  onClick={() => {
                    setShowForm(!showForm);
                    setPostId(post.id);
                  }}
                  startIcon={<EditIcon />}
                >
                  Edit
                </Button>
              </AccordionDetails>
            </Accordion>
          ))}
        </Container>
      </Container>
    </>
  );
};

export default Authorsgroup;

问题原因分析

  1. 硬编码分组渲染:组件手动写死了Tapesh、HappyManager等固定分组的展示逻辑,当编辑修改作者名后,文章会被归入新的分组key,但组件不会渲染该新分组,导致数据看似被清除;全选时父组件数据集完整,reduce后的分组包含新key,但当前组件无法展示。
  2. state更新依赖缺失:useEffect仅监听groupDropdownValue和showForm,未包含核心数据源posts,当posts因编辑更新后,authorGroupValues无法同步最新分组数据。

解决方案

方案1:动态遍历所有分组(推荐)

移除硬编码的分组渲染,动态遍历authorGroupValues的所有key,确保所有分组(含编辑后新增的)都能展示:

// 替换原return中的所有固定分组Container,改为以下代码
<Container>
  {Object.entries(authorGroupValues).map(([authorKey, postsList]) => {
    // 自定义作者分组颜色映射
    const colorMap = {
      Tapesh: "#EB1283",
      HappyManager: "orange",
      HappyDeveloper: "green",
      HappyUser: "red"
    };
    const groupColor = colorMap[authorKey] || "#333";
    
    return (
      <Container key={authorKey} style={{ marginTop: "3rem" }}>
        {postsList.map((post) => (
          <Accordion key={post.id}> {/* 用post.id替代index作为key,避免渲染异常 */}
            <AccordionSummary
              expandIcon={<ExpandMoreIcon />}
              aria-controls={`panel-${post.id}-content`}
              id={`panel-${post.id}-header`}
            >
              <Typography variant="h6" style={{ color: groupColor }}>
                {post.id} {post.author} {post.location}
              </Typography>
            </AccordionSummary>
            <AccordionDetails>
              <Typography variant="h4">{post.location}</Typography>
              <Typography>{post.text}</Typography>
              <Button
                variant="outlined"
                onClick={() => {
                  setShowForm(!showForm);
                  setPostId(post.id);
                }}
                startIcon={<EditIcon />}
              >
                Edit
              </Button>
            </AccordionDetails>
          </Accordion>
        ))}
      </Container>
    );
  })}
</Container>

方案2:修复state更新依赖

将posts加入useEffect依赖数组,确保数据源更新时分组state同步更新:

useEffect(() => {
  setAuthorGroupValues(authorGroup);
}, [groupDropdownValue, showForm, posts]); // 添加posts依赖

方案3:移除冗余state(更简洁)

authorGroup基于posts实时计算,无需额外的authorGroupValues state,直接使用authorGroup即可避免同步问题:

// 移除以下代码
const [authorGroupValues, setAuthorGroupValues] = useState(authorGroup);

useEffect(() => {
  setAuthorGroupValues(authorGroup);
  console.log(authorGroupValues);
}, [groupDropdownValue, showForm]);

// 所有用到authorGroupValues的地方替换为authorGroup

额外优化点

  • 使用post.id作为Accordion的key,比index更稳定,避免列表更新时的渲染异常。
  • 通过颜色映射表动态设置分组颜色,减少硬编码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 08:21:35