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

Strapi+React中Material UI DataGrid嵌套节点显示异常问题

解决Material UI DataGrid嵌套节点显示与Contact模态框Undefined问题

问题根源分析

  1. DataGrid Leads列显示异常:你在columns配置中为leads列写了冗余且错误的valueGetter——转换companies数据时,已经将leads数组处理成字符串并挂载到row对象上,但valueGetter仍尝试从params.row.attributes取值(此时row里已无attributes字段)。
  2. Contact模态框值为Undefined:若使用Strapi v4,关联字段(如contact)返回结构为{ data: { attributes: {...} } },你直接取params.row.contact拿到的是外层容器对象,而非真正的属性数据;同时你的GraphQL查询可能未遵循Strapi v4的关联字段嵌套规则(需遍历data和attributes)。

修正后的完整代码

import React, { useState } from 'react';
import { useQuery } from '@apollo/client';
import { DataGrid } from '@material-ui/data-grid';
import { Modal, Typography, Box, List, ListItem, ListItemText } from '@material-ui/core';
import ReactMarkdown from 'react-markdown';
import gql from 'graphql-tag';

// 适配Strapi v4的GraphQL查询结构(使用v3可忽略此调整)
const GET_COMPANIES_QUERY = gql`
  query {
    companies {
      data {
        id
        attributes {
          companyName
          status
          internship
          futureMinEmp
          futureMaxEmp
          leads {
            data {
              attributes {
                leadSourceName
              }
            }
          }
          contact {
            data {
              attributes {
                firstName
                lastName
                jobtitle
                lastContact
                nextContact
                notes {
                  data {
                    attributes {
                      date
                      note
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
`;

const columns = [
  { field: 'companyName', headerName: 'Company Name', flex: 1, headerAlign: 'center' },
  { field: 'status', headerName: 'Status', flex: 1, headerAlign: 'center' },
  { field: 'internship', headerName: 'Internship', flex: 1, headerAlign: 'center' },
  { field: 'futureMinEmp', headerName: 'Min Employees', flex: 1, headerAlign: 'center' },
  { field: 'futureMaxEmp', headerName: 'Max Employees', flex: 1, headerAlign: 'center' },
  // 移除错误的valueGetter,直接使用处理好的leads字段
  { field: 'leads', headerName: 'Leads', flex: 1, headerAlign: 'center' },
];

const CompaniesPage = () => {
  const [selectedContact, setSelectedContact] = useState(null);
  const { loading, error, data } = useQuery(GET_COMPANIES_QUERY);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error :(</p>;

  const companies = data?.companies?.data?.map((company) => {
    // 处理Leads数据(适配Strapi v4结构)
    const leadList = company.attributes?.leads?.data || [];
    const leads = leadList.length > 0
      ? leadList.map(lead => lead.attributes.leadSourceName).join(', ')
      : 'No leads';

    // 处理Contact数据(提取真正的属性对象)
    const contactData = company.attributes?.contact?.data?.attributes || null;
    // 处理Notes数据(转换为属性数组)
    if (contactData) {
      contactData.notes = contactData.notes?.data?.map(note => note.attributes) || [];
    }

    return {
      id: company.id,
      ...company.attributes,
      leads,
      contact: contactData, // 挂载处理后的contact对象
    };
  });

  const handleRowClick = (params) => {
    setSelectedContact(params.row.contact);
  };

  const handleCloseModal = () => {
    setSelectedContact(null);
  };

  return (
    <>
      <DataGrid
        rows={companies}
        columns={columns}
        autoHeight
        onRowClick={handleRowClick}
        getRowClassName={(params) => params.row.contact ? 'clickable-row' : ''}
      />

      <Modal 
        open={!!selectedContact} 
        onClose={handleCloseModal} 
        style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}
      >
        <Box bgcolor="background.paper" boxShadow={2} p={3} style={{ outline: 'none', minWidth: 400 }}>
          {selectedContact ? (
            <>
              <Typography variant="h4" gutterBottom>
                {selectedContact.firstName} {selectedContact.lastName}
              </Typography>
              <Typography variant="subtitle1" gutterBottom>
                {selectedContact.jobtitle}
              </Typography>
              <Typography variant="subtitle2" gutterBottom>
                Last Contact: {selectedContact.lastContact}
              </Typography>
              <Typography variant="subtitle2" gutterBottom>
                Next Contact: {selectedContact.nextContact}
              </Typography>
              <Typography variant="h6" gutterBottom style={{ marginTop: 16 }}>
                Notes
              </Typography>
              <List>
                {selectedContact.notes.length > 0 ? (
                  selectedContact.notes.map((note, index) => (
                    <ListItem key={index}>
                      <ListItemText 
                        primary={note.date} 
                        secondary={<ReactMarkdown>{note.note}</ReactMarkdown>} 
                      />
                    </ListItem>
                  ))
                ) : (
                  <Typography variant="body2">No notes available</Typography>
                )}
              </List>
            </>
          ) : null}
        </Box>
      </Modal>
    </>
  );
};

export default CompaniesPage

关键修改说明

  1. GraphQL查询修正:针对Strapi v4关联字段结构,补充data和attributes层级,确保正确获取嵌套数据。
  2. Leads列配置简化:移除错误的valueGetter,直接使用转换后的leads字符串字段。
  3. Contact数据处理:从Strapi返回的关联结构中提取真正的属性对象,确保模态框能读取firstName等字段。
  4. Notes数据转换:将Notes的嵌套结构转换为属性数组,方便在模态框中遍历展示。
  5. 模态框优化:增加Notes列表展示,完善空状态处理,移除不必要的event.preventDefault()(Modal关闭无需阻止默认行为)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 23:30:45