首页 > 解决方案 > 如何使用 API 返回的多个字段构建表列?

问题描述

我需要预处理来自 API 的数据。原始数据采用以下格式:

在此处输入图像描述

我想动态构建一个表,其中的列应该使用字段task_namesaved_answers. 请注意,saved_answers可能包含不同的子字段,具体取决于task_name. 换句话说,并不saved_answers总是包含value21value22和。value23value24

下面我展示一个表格的例子。

============================================================================================================
| user_id  |  task11-value21  |   task11-value22  |   task11-value23  |  task11-value24  | task13-valueMu...
============================================================================================================
| 111      |  1               |   1               |   1               |  1               | 5
... 

到目前为止,我只能从 API 检索数据并在表中显示特定列。我将非常感谢任何帮助。谢谢。

import React, { useEffect } from 'react'
import { makeStyles } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';
import axios from 'axios'
import config from '../../config/config.json';

const useStyles = makeStyles((theme) => ({
    root: {
        width: '100%',
    },
    heading: {
        fontSize: theme.typography.pxToRem(18),
        fontWeight: theme.typography.fontWeightBold,
    },
    content: {
        fontSize: theme.typography.pxToRem(14),
        fontWeight: theme.typography.fontWeightRegular,
        textAlign: "left",
        marginTop: theme.spacing.unit*3,
        marginLeft: theme.spacing.unit*3,
        marginRight: theme.spacing.unit*3
    },
    table: {
        minWidth: 650,
    },
    tableheader: {
        fontWeight: theme.typography.fontWeightBold,
        color: "#ffffff",
        background: "#3f51b5"
    }
}));


export function Main() {

    const [groupKey,setGroupKey] = React.useState([]);

    const classes = useStyles();

    const options = {
        'headers': {
            'Authorization': `Bearer ${localStorage.getItem('accessToken')}`
        }
    }

    useEffect(() => {
        axios.get(config.api.url + '/api/test', options)
            .then( (groups) => {
                setGroupKey(groups);
                console.log(groups);
            })
            .catch( (error) => {
                console.log(error);
            })
    }, []);

    return (
        <div className={classes.root}>

            <Grid container spacing={3}>
                <Grid item xs={12} className={classes.content}>
                    <TableContainer component={Paper}>
                        <Table className={classes.table}>
                            <TableHead>
                                <TableRow>
                                    <TableCell className={classes.tableheader}>Group</TableCell>
                                    <TableCell className={classes.tableheader} colSpan={3}>Task name</TableCell>
                                </TableRow>
                            </TableHead>
                            <TableBody>
                                {groupKey.map( (row, index) => (
                                    <TableRow key={index} selected="false">
                                        <TableCell>{row.user_id}</TableCell>
                                        <TableCell>{row.task_name}</TableCell>
                                    </TableRow>))}
                            </TableBody>
                        </Table>
                    </TableContainer>

                </Grid>    
            </Grid>
        </div>
    )
}

更新:

import '../../App.css';
import React, { useEffect } from 'react'
import PropTypes from 'prop-types';
import { makeStyles, useTheme } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import TablePagination from '@material-ui/core/TablePagination';
import TableFooter from '@material-ui/core/TableFooter';
import IconButton from '@material-ui/core/IconButton';
import FirstPageIcon from '@material-ui/icons/FirstPage';
import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft';
import KeyboardArrowRight from '@material-ui/icons/KeyboardArrowRight';
import LastPageIcon from '@material-ui/icons/LastPage';
import Paper from '@material-ui/core/Paper';
import axios from 'axios'
import config from '../../config/config.json';

const useStyles = makeStyles((theme) => ({
    root: {
        width: '100%',
    },
    heading: {
        fontSize: theme.typography.pxToRem(18),
        fontWeight: theme.typography.fontWeightBold,
    },
    content: {
        fontSize: theme.typography.pxToRem(14),
        fontWeight: theme.typography.fontWeightRegular,
        textAlign: "left",
        marginTop: theme.spacing.unit*3,
        marginLeft: theme.spacing.unit*3,
        marginRight: theme.spacing.unit*3
    },
    table: {
        minWidth: 650,
    },
    tableheader: {
        fontWeight: theme.typography.fontWeightBold,
        color: "#ffffff",
        background: "#3f51b5"
    },
    tableCell: {
        color: "#000000",
        background: "#ffffff"
    },
    button: {
        fontSize: "12px",
        minWidth: 100
    },
}));


function TablePaginationActions(props) {
    const classes = useStyles();
    const theme = useTheme();
    const { count, page, rowsPerPage, onChangePage } = props;
  
    const handleFirstPageButtonClick = (event) => {
      onChangePage(event, 0);
    };
  
    const handleBackButtonClick = (event) => {
      onChangePage(event, page - 1);
    };
  
    const handleNextButtonClick = (event) => {
      onChangePage(event, page + 1);
    };
  
    const handleLastPageButtonClick = (event) => {
      onChangePage(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1));
    };
  
    return (
      <div className={classes.root}>
        <IconButton
          onClick={handleFirstPageButtonClick}
          disabled={page === 0}
          aria-label="first page"
        >
          {theme.direction === 'rtl' ? <LastPageIcon /> : <FirstPageIcon />}
        </IconButton>
        <IconButton onClick={handleBackButtonClick} disabled={page === 0} aria-label="previous page">
          {theme.direction === 'rtl' ? <KeyboardArrowRight /> : <KeyboardArrowLeft />}
        </IconButton>
        <IconButton
          onClick={handleNextButtonClick}
          disabled={page >= Math.ceil(count / rowsPerPage) - 1}
          aria-label="next page"
        >
          {theme.direction === 'rtl' ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
        </IconButton>
        <IconButton
          onClick={handleLastPageButtonClick}
          disabled={page >= Math.ceil(count / rowsPerPage) - 1}
          aria-label="last page"
        >
          {theme.direction === 'rtl' ? <FirstPageIcon /> : <LastPageIcon />}
        </IconButton>
      </div>
    );
  }


  function getGridHeader(config) {
    const gridHeader = ["user_id"];
    console.log(config);
    const savedAnswers = Object.keys(JSON.parse(config.saved_answers));
    savedAnswers.map(savedAnswer => {
      gridHeader.push(`${config.task_name}-${savedAnswer}`)
    });
    return gridHeader;
  }

  
  function getGridData(config) {
    const gridData = [config.user_id];
    const savedAnswers = JSON.parse(config.saved_answers);
    Object.keys(savedAnswers).map( savedAnswer => {
      gridData.push(savedAnswers[savedAnswer]);
    });
    return gridData;
  }

  
  TablePaginationActions.propTypes = {
    count: PropTypes.number.isRequired,
    onChangePage: PropTypes.func.isRequired,
    page: PropTypes.number.isRequired,
    rowsPerPage: PropTypes.number.isRequired,
  };


export function Main() {

    const [groupKey,setGroupKey] = React.useState([]);
    const [page, setPage] = React.useState(0);
    const [rowsPerPage, setRowsPerPage] = React.useState(5);
    const emptyRows = rowsPerPage - Math.min(rowsPerPage, groupKey.length - page * rowsPerPage);

    const gridHeader = getGridHeader(groupKey);
    const gridData = getGridData(groupKey);

    const handleChangePage = (event, newPage) => {
        setPage(newPage);
    };

    const handleChangeRowsPerPage = (event) => {
        setRowsPerPage(parseInt(event.target.value, 10));
        setPage(0);
    };

    const classes = useStyles();

    const options = {
        'headers': {
            'Authorization': `Bearer ${localStorage.getItem('accessToken')}`
        }
    }

    useEffect(() => {
        axios.get(config.api.url + '/api/test', options)
            .then( (groups) => {
                setGroupKey(groups.data.subtask);
            })
            .catch( (error) => {
                console.log(error);
            })
    }, []);

    return (
        <div className={classes.root}>

            <Grid container spacing={3}>
                <Grid item xs={12} className={classes.content}>

                <TableContainer component={Paper}>
                    <Table className={classes.table}>
                        <TableHead>
                            <TableRow className={classes.tableheader}>
                                {gridHeader.map( (headerTitle, index) => (
                                <TableCell key={index}>{headerTitle}</TableCell>
                                ))}
                            </TableRow>
                        </TableHead>
                        <TableBody>
                        {(rowsPerPage > 0
                            ? gridData.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
                            : gridData
                        ).map((cellValue, index) => (
                            <TableRow key={index} selected="false">
                                <TableCell className={classes.tableCell}component="th" scope="row">{cellValue}</TableCell>
                            </TableRow>
                        ))}

                        {emptyRows > 0 && (
                            <TableRow style={{ height: 53 * emptyRows }}>
                            <TableCell colSpan={6} />
                            </TableRow>
                        )}
                        </TableBody>
                        <TableFooter>
                            <TableRow>
                                <TablePagination
                                    rowsPerPageOptions={[5, 10, 25, { label: 'All', value: -1 }]}
                                    colSpan={3}
                                    count={groupKey.length}
                                    rowsPerPage={rowsPerPage}
                                    page={page}
                                    SelectProps={{
                                        inputProps: { 'aria-label': 'groups per page' },
                                        native: true,
                                    }}
                                    onChangePage={handleChangePage}
                                    onChangeRowsPerPage={handleChangeRowsPerPage}
                                    ActionsComponent={TablePaginationActions}
                                />
                            </TableRow>
                        </TableFooter>
                    </Table>
                    </TableContainer>

                </Grid>    
            </Grid>
        </div>
    )
}

标签: javascriptreactjsmaterial-ui

解决方案


所以,算法如下:

  1. 从原始数据生成标头数组
  2. 根据 user_id 为表体数据生成数组

我希望你能做到。

使用这两个数组,您可以迭代并创建数据表,例如:

在此处输入图像描述

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';

const useStyles = makeStyles({
  table: {
    minWidth: 650,
  },
});

function generateRandomSavedAnswer(rowIndex, maxNumberOfSavedAnswers) {
  //const numberOfSavedAnswers = Math.floor(Math.random()*maxNumberOfSavedAnswers);
  const savedAnswers = {};
  for(let i=0; i<maxNumberOfSavedAnswers; i++) {
    savedAnswers[`value${rowIndex}${i}`] = rowIndex+i;
  }
  return savedAnswers;
}
function generateGridRawData() {
  let gridData = [];
  for(let i=0; i<10; i++) {
    gridData.push({
      saved: true,
      saved_answers: JSON.stringify(generateRandomSavedAnswer(10, 5)),
      submited: true,
      task_name: 'task12',
      user_id: Math.floor(Math.random()*3),
      __v: 0,
      _id: Math.round(Math.sin(i*0.01)*100)
    });
  }
  return gridData;
}

function getGridHeader(config) {
  const gridHeader = ["user_id"];
  const savedAnswers = Object.keys(JSON.parse(config.saved_answers));
  savedAnswers.map(savedAnswer => {
    gridHeader.push(`${config.task_name}-${savedAnswer}`)
  });
  return gridHeader;
}

function getGridData(config) {
  const gridData = [config.user_id];
  const savedAnswers = JSON.parse(config.saved_answers);
  Object.keys(savedAnswers).map( savedAnswer => {
    gridData.push(savedAnswers[savedAnswer]);
  });
  return gridData;
}

export default function SimpleTable() {
  const classes = useStyles();
  const gridRawData = generateGridRawData();
  const gridHeader = getGridHeader(gridRawData[0]);
  const gridData = getGridData(gridRawData[0]);

  return (
    <TableContainer component={Paper}>
      <Table className={classes.table} aria-label="simple table">
        <TableHead>
          <TableRow>
            {gridHeader.map( (headerTitle, index) => (
              <TableCell key={index}>{headerTitle}</TableCell>
            ))}
          </TableRow>
        </TableHead>
        <TableBody>
          <TableRow>
            {gridData.map( (cellValue, index) => (
              <TableCell key={index}>{cellValue}</TableCell>
            ))}
          </TableRow>
        </TableBody>
      </Table>
    </TableContainer>
  );
}

推荐阅读