传递道具以制作搜索栏时出错

Error while passing proprs to make a search bar

我正在尝试创建一个搜索输入,该输入将按用户将输入的名称进行过滤。我有两个组件,一个是搜索输入 (app.js),另一个是 table(table.js).

我能够获取搜索输入的当前值 (app.js),但是当试图将其作为道具传递给 table (table.js) 时,它给出了一个错误。

我是 React 新手,但根据我的理解,我认为我在将 useState 作为 props 传递时遇到了问题。

1.搜索输入代码 (app.js)

I used onChange event as to get the current value when the input field change.

<div className="search">
              <div className={classes.search}>
                <div className={classes.searchIcon}>
                  <SearchIcon />
                </div>
                <InputBase
                  placeholder="Search..."
                  classes={{
                    root: classes.inputRoot,
                    input: classes.inputInput,
                  }}

                  onChange={getSearchTerm}

                />
              </div>
            </div>

getSearchTerm 函数获取当前输入值

const [searchTerm, setSearchTerm] = useState("");

const getSearchTerm = (event) => {

const searchWord = event.target.value;
console.log(searchWord);
setSearchTerm(searchWord)
}

2。 Table (app.js) 传递道具

passing the props in the filter function. So can get filterd when a input would be entered in search input.

export default function EnhancedTable(props) {

console.log("these r props for table component", props);

<TableBody>
                        {data
                            .filter((item) => {
                                if (props.searchTerm == "") {
                                    return item;
                                } else if (item.clientName.toLowerCase().includes(props.searchTerm.toLowerCase())) {
                                    return item;
                                }
                            })
                            .map((item, index) => {
                                return (

                                    <TableRow
                                        hover
                                        role="checkbox"
                                        tabIndex={-1}
                                    >
                                        <TableCell padding="checkbox">
                                            <Checkbox
                                            />
                                        </TableCell>
                                        <TableCell component="th" scope="row" padding="none">{item.clientName}</TableCell>
                                        <TableCell align="right">{item.clientEmail}</TableCell>
                                        <TableCell align="right">{item.clientWorkPhone}</TableCell>
                                        <TableCell align="right">{item.clientIndustry}</TableCell>
                                        <TableCell align="right">{item.tenantId}</TableCell>
                                        <TableCell align="right">{item.clientWebsite}</TableCell>
                                        <TableCell align="right"><Button style={{ backgroundColor: 'transparent', color: '#5900B4' }} variant="outlined" color="primary" href="#outlined-buttons" >{<CreateIcon />}</Button>
                                        </TableCell>
                                    </TableRow>
                                )
                            })}

                    </TableBody>

3。获取

时出错

[我遇到的错误在这里][1]

4.完整搜索输入 (app.js) 文件更清晰

function App() {

  const [searchTerm, setSearchTerm] = useState("");

  const classes = useStyles();

  const getSearchTerm = (event) => {
    //console.log(inputEl.current.value);

    const searchWord = event.target.value;
    console.log(searchWord);
    setSearchTerm(searchWord)


  }

  return (
    <div className="App">
      <div className="wrapper">
        <div className="container-table">
          <div className="head">
            <h5 className='management'>MANAGEMENT</h5>
            <div className="head-middle">
              <h2>Clients</h2>
              <div className="button-collection">
                <Button style={{ backgroundColor: '#5900B4', color: '#FFFFFF', fontSize: '15px', fontWeight: '900', width: '206px', height: '42px' }}
                  variant="contained"
                  className='add-collection-btn'
                  startIcon={<AddIcon />}
                >
                  New Collection
                </Button>
              </div>
            </div>
            <div className="head-bottom">
              <div className="head-button">
                <div className="search">
                  <div className={classes.search}>
                    <div className={classes.searchIcon}>
                      <SearchIcon />
                    </div>
                    <InputBase
                      placeholder="Search..."
                      classes={{
                        root: classes.inputRoot,
                        input: classes.inputInput,
                      }}

                      onChange={getSearchTerm}

                    />
                  </div>
                </div>
                <Button style={{ backgroundColor: 'white', color: 'black', width: '100px', height: '40px', marginLeft: '20px', marginRight: '20px' }} variant="contained">Search</Button>
                <Button style={{ backgroundColor: 'white', color: 'black', width: '100px', height: '40px' }} variant="contained">Clear</Button>
              </div>

              <Button style={{
                backgroundColor: 'transparent', color: '#5900B4', width: '206px', height: '42px', borderColor: '#5900B4', fontSize: '15px', fontWeight: '900'
              }} variant="outlined" color="primary"
                startIcon={<FilterListIcon />}
              >
                SHOW FILTER
              </Button>
            </div>
            <div className="table">
              <EnhancedTable
                onChange={setSearchTerm}

              />
            </div>

          </div>
        </div>

      </div>
    </div>
  );
}

export default App;

5.为清楚起见,完整 table (table.js) 文件

const headCells = [
    { id: 'name', numeric: false, disablePadding: true, label: 'Client Name' },
    { id: 'email', numeric: true, disablePadding: false, label: 'Email' },
    { id: 'phone', numeric: true, disablePadding: false, label: 'Phone' },
    { id: 'industry', numeric: true, disablePadding: false, label: 'Industry' },
    { id: 'contact', numeric: true, disablePadding: false, label: 'Point of Contact' },
    { id: 'website', numeric: true, disablePadding: false, label: 'Website' },
    { id: 'btn-icon', numeric: true, disablePadding: false, label: '' },
];

function EnhancedTableHead(props) {
    const { classes, onSelectAllClick, order, orderBy, numSelected, rowCount } = props;


    return (
        <TableHead>
            <TableRow style={{ backgroundColor: '#F5F6F8', height: '120px' }}>
                <TableCell padding="checkbox">
                    <Checkbox
                        indeterminate={numSelected > 0 && numSelected < rowCount}
                        checked={rowCount > 0 && numSelected === rowCount}
                        onChange={onSelectAllClick}
                        inputProps={{ 'aria-label': 'select all desserts' }}
                    />
                </TableCell>
                {headCells.map((headCell) => (
                    <TableCell
                        key={headCell.id}
                        align={headCell.numeric ? 'right' : 'left'}
                        padding={headCell.disablePadding ? 'none' : 'normal'}
                    >
                        {headCell.label}
                    </TableCell>
                ))}
            </TableRow>
        </TableHead>
    );
}

EnhancedTableHead.propTypes = {
    classes: PropTypes.object.isRequired,
    numSelected: PropTypes.number.isRequired,
    order: PropTypes.oneOf(['asc', 'desc']).isRequired,
    orderBy: PropTypes.string.isRequired,
};

const useToolbarStyles = makeStyles((theme) => ({
    root: {
        paddingLeft: theme.spacing(2),
        paddingRight: theme.spacing(1),
    },
    highlight:
        theme.palette.type === 'light'
            ? {
                color: theme.palette.secondary.main,
                backgroundColor: lighten(theme.palette.secondary.light, 0.85),
            }
            : {
                color: theme.palette.text.primary,
                backgroundColor: theme.palette.secondary.dark,
            },
    title: {
        flex: '1 1 100%',
    },
}));

const EnhancedTableToolbar = (props) => {
    const classes = useToolbarStyles();
    return (
        <Toolbar>
            {
                <Typography className={classes.title} variant="h6" id="tableTitle" component="div">
                    Clients
                </Typography>
            }
        </Toolbar>
    );
};

EnhancedTableToolbar.propTypes = {
    numSelected: PropTypes.number.isRequired,
};

const useStyles = makeStyles((theme) => ({
    root: {
        width: '100%',
    },
    paper: {
        width: '100%',
        marginBottom: theme.spacing(2),
    },
    table: {
        minWidth: 750,
    },
    visuallyHidden: {
        border: 0,
        clip: 'rect(0 0 0 0)',
        height: 1,
        margin: -1,
        overflow: 'hidden',
        padding: 0,
        position: 'absolute',
        top: 20,
        width: 1,
    },
}));

export default function EnhancedTable(props) {

    console.log("these r props for table component", props);


    const classes = useStyles();
    const [order, setOrder] = React.useState('asc');
    const [orderBy, setOrderBy] = React.useState('calories');
    const [selected, setSelected] = React.useState([]);
    const [page, setPage] = React.useState(0);
    const [dense, setDense] = React.useState(false);
    const [rowsPerPage, setRowsPerPage] = React.useState(5);


    const isSelected = (name) => selected.indexOf(name) !== -1;

    const [data, setData] = useState([]);

    const getData = async () => {
        try {
            const data = await axios.get("something");
            
            setData(data.data);
        } catch (e) {
            console.log("this is error for fetching data", e)
        }
    };


    useEffect(() => {
        getData();
    }, [])


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

            <Paper className={classes.paper}>
                <EnhancedTableToolbar numSelected={selected.length} />
                <TableContainer>
                    <Table
                        className={classes.table}
                        aria-labelledby="tableTitle"
                        size={dense ? 'small' : 'medium'}
                        aria-label="enhanced table"
                    >
                        <EnhancedTableHead
                            classes={classes}
                            numSelected={selected.length}
                            order={order}
                            orderBy={orderBy}
                        />
                        <TableBody>
                            {data
                                /*.filter((item) => {
                                    if (searchTerm == "") {
                                        return item;
                                    } else if (item.clientName.toLowerCase().includes(searchTerm.toLowerCase())) {
                                        return item;
                                    }
                                })*/
                                .map((item, index) => {
                                    return (

                                        <TableRow
                                            hover
                                            role="checkbox"
                                            tabIndex={-1}
                                        >
                                            <TableCell padding="checkbox">
                                                <Checkbox
                                                />
                                            </TableCell>
                                            <TableCell component="th" scope="row" padding="none">{item.clientName}</TableCell>
                                            <TableCell align="right">{item.clientEmail}</TableCell>
                                            <TableCell align="right">{item.clientWorkPhone}</TableCell>
                                            <TableCell align="right">{item.clientIndustry}</TableCell>
                                            <TableCell align="right">{item.tenantId}</TableCell>
                                            <TableCell align="right">{item.clientWebsite}</TableCell>
                                            <TableCell align="right"><Button style={{ backgroundColor: 'transparent', color: '#5900B4' }} variant="outlined" color="primary" href="#outlined-buttons" >{<CreateIcon />}</Button>
                                            </TableCell>
                                        </TableRow>
                                    )
                                })}

                        </TableBody>
                    </Table>
                </TableContainer>

            </Paper>

        </div>
    );
}

问题是 searchTerm 不在您的组件范围内,所以这一行...

item.clientName.toLowerCase().includes(searchTerm.toLowerCase())

抛出您看到的错误

Cannot read property 'toLowerCase' of undefined

您需要将所需的道具传递给您的组件。

<EnhancedTable searchTerm={searchTerm} />

这也是使用 React 的 useMemo 钩子生成过滤结果的绝佳机会

const { searchTerm } = props // extract searchTerm from props

const filtered = useMemo(() => {
  if (!searchTerm) {
    return data
  }

  const term = searchTerm.toLowerCase()
 
  return data.filter(({ clientName }) =>
    clientName.toLowerCase().includes(term))
}, [ data, searchTerm ])

现在您可以在 return 值中使用 filtered 代替 data

<TableBody>
  {filtered.map((item, index) => {
    // etc
  })}
</TableBody>