如果子组件中有相关数据,则仅在父组件中显示图标,但为了获得数据,我必须单击该图标

Only display icon in parent if there's the relevant data in child component, but in order to have the data I must click on that icon

好吧,我什至花了一段时间才提出这个问题。这更多的是与设计策略有关,而不是任何东西。

我有一个包含 table 的视图,它显示了 table 的所有 users.Each 行的列表,左侧有一个图标,可以展开(或折叠)一个名为 UsersTrainingSummary 的组件仅带来一些特定数据的摘要。见图:

下面是这个视图组件的完整代码:

import React from 'react';
import { Card, CardContent, CardHeader, Chip, Divider, Grid, Typography } from '@material-ui/core';
import { gridSpacing } from '../../../store/constant';
import TableContainer from '@material-ui/core/TableContainer';
import Table from '@material-ui/core/Table';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import MuiTableCell from '@material-ui/core/TableCell';
import TableBody from '@material-ui/core/TableBody';
import { makeStyles,  withStyles } from '@material-ui/core/styles';
import {Link} from "react-router-dom";
import IconButton from '@material-ui/core/IconButton';
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
import KeyboardArrowUpIcon from '@material-ui/icons/KeyboardArrowUp';
import moment from 'moment';

import UsersTrainingSummary from './UsersTrainningSummary';
import useLocalStorage from 'react-use-localstorage';
import { useQuery } from '@apollo/client';
import ALL_USERS from '../../../graphql/AllUsers';
import Loader from '../../../component/Loader/Loader';


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

const TableCell = withStyles({
    root: {
        borderBottom: "none"
    }
})(MuiTableCell);

function createData(userId, username, firstName, lastName, dateJoined, lastLogin, email, isActive, trainings ) {
    return { userId, username, firstName, lastName, dateJoined, lastLogin, email,isActive, trainings };
}

const UserDashboard = () => {
    const classes = useStyles();
    const [storage, setStorage] = useLocalStorage('orgId');
    const orgId = storage
    const { data, error , loading} = useQuery(ALL_USERS, {
        variables: {
            orgId: Number(orgId)
        },
    });


    function Row(props){
        const { row } = props;
        const [open, setOpen] = React.useState(false);
        return (
            <React.Fragment>
                <TableRow key={row.userId}>
                    <TableCell>
                        <IconButton aria-label="expand row" size="small" onClick={() => setOpen(!open)}>
                            {open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}
                        </IconButton>
                    </TableCell>
                    <Link to={{pathname: `/users/${row?.userId}`, state: { user: row}}}
                          style={{ textDecoration: 'none' }}>
                        <TableCell
                            className={classes.root} hover={true}
                            component="th" scope="row">{row?.username}
                        </TableCell>
                    </Link>
                    <TableCell>{row.firstName}</TableCell>
                    <TableCell>{row.lastName}</TableCell>
                    <TableCell>{moment(row?.dateJoined).format('MM/DD/YYYY')}</TableCell>
                    <TableCell>{moment(row?.lastLogin).format('MM/DD/YYYY')}</TableCell>
                    <TableCell>{row?.email}</TableCell>
                    <TableCell>{row?.isActive? <React.Fragment>Yes</React.Fragment> : <React.Fragment>No</React.Fragment>}</TableCell>
                </TableRow>
                <TableRow>
                    <TableCell style={{ paddingBottom: 0, paddingTop: 0 }} colSpan={6}>
                        {open && <UsersTrainingSummary userId={row.userId} trainings={row.trainings}/>}
                    </TableCell>
                </TableRow>
            </React.Fragment>
        )
    }
    if(data) {
        let userList = data.organization?.user
        const rows = [];
        if (userList) {
            userList.map((user) => {
                rows.push(createData(user.id, user.username, user.firstName, user.lastName, user.dateJoined, user.lastLogin,
                    user.email, user.isActive, user.trainings))
            })
        }
        return (
            <Grid container spacing={gridSpacing}>
                <Grid item xs={12}>
                    <Card>
                        <CardHeader
                            title={
                                <Typography component="div" className="card-header">
                                    List of all trainees
                                </Typography>
                            }
                        />
                        <Divider/>
                        <CardContent className="p-0">
                            <TableContainer>
                                <Table className={classes.table} aria-label="simple table">
                                    <TableHead>
                                        <TableRow>
                                            <TableCell></TableCell>
                                            <TableCell>Username</TableCell>
                                            <TableCell>First Name</TableCell>
                                            <TableCell>Last Name</TableCell>
                                            <TableCell>Date Joined</TableCell>
                                            <TableCell>Last Login</TableCell>
                                            <TableCell>Email</TableCell>
                                            <TableCell>Is Active</TableCell>

                                        </TableRow>
                                    </TableHead>
                                    <TableBody>
                                        {rows?.length > 0 && rows.map((row) => (
                                            <Row key={row?.userId} row={row}/>
                                        ))}
                                    </TableBody>
                                </Table>
                            </TableContainer>
                        </CardContent>
                    </Card>
                </Grid>
            </Grid>
        );
    }
    else
        return ( <Loader />)
}

export default UserDashboard

因为如果您尝试一次为太多用户带来汇总数据的查询可能会非常慢,因为数据库中涉及的 tables 具有大量数据,并且因为大多数时候你只需要一个或几个用户,我决定使用一个懒惰的策略:只有当用户点击那个箭头图标时,组件 UsersTrainingSummary 才会呈现,我有 graphql 查询从中获取数据后端和 还执行所有必要的逻辑来呈现 Collapse 组件。

我现在想要实现的是只为实际有东西要显示的用户显示该图标,例如查询不会从 BE 带来空结果,因为作为用户,我觉得拥有该图标有点误导这样您就可以单击并看到一条消息“哦...这里什么都没有”。但是,由于我需要先执行查询才能知道是否有要显示的内容,所以对我来说这似乎是不可能的,除非我先为所有用户执行该查询,这是我真的不想做的事情,因为性能的权重远大于用户友好界面的权重。

或者,有什么方法可以实现吗?

如评论中所述,通过添加布尔字段(例如“hasMoreInfo”),查询数据库以查找所有拥有更多信息的用户的替代方法可能是在后端管理问题到您用来填充第一个视图的 table 并使用该值来决定是否呈现图标。