Ошибка при передаче proprs для создания строки поиска

#javascript #reactjs #jsx #react-props

Вопрос:

Я пытаюсь выполнить поисковый ввод, который будет фильтроваться по имени, которое введет пользователь. У меня есть два компонента, один из которых-поисковый ввод (app.js) а другой сидит за столом(table.js).

Я могу получить текущее значение ввода поиска (app.js) но при попытке передать его в качестве реквизита в таблице (table.js) это выдает ошибку.

Я новичок в реагировании, но, насколько я понимаю, у меня возникли проблемы с передачей useState в качестве реквизита.

1. Код для ввода поиска (app.js)

Я использовал событие onChange, чтобы получить текущее значение при изменении поля ввода.

 <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. Таблица (app.js) передача реквизита

передача реквизитов в функции фильтра. Таким образом, можно получить filterd, когда ввод будет введен в поисковый ввод.

 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. Error getting

[The error I’m getting is here][1]

4. Full Search input (app.js) file for more clarity

 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.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 amp;amp; numSelected < rowCount}
                        checked={rowCount > 0 amp;amp; 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>
    );
}
 

Комментарии:

1. да, это так, я просто не вставлял эту часть, думал, что это будет оффтопик, я добавлю полный файл.

2. Вы имеете в виду, что у меня проблемы с функцией карты?

3. потому что, когда я комментирую функцию фильтра, она идеально отображает все данные. но как только я добавляю реквизиты и раскомментирую функцию фильтра, она начинает выдавать ошибку.

4. Где это searchTerm определено в вашем EnhancedTable компоненте?

5. Вы не передаете никаких реквизитов <EnhancedTable> , кроме onChange как от App.js.

Ответ №1:

Проблема в том, что searchTerm это не входит в сферу действия вашего компонента, поэтому эта строка…

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

выдает ошибку, которую вы видите

Не удается прочитать свойство «В нижнем регистре» неопределенного

Вам нужно передать необходимые реквизиты вашему компоненту.

 <EnhancedTable searchTerm={searchTerm} />
 

Это также прекрасная возможность использовать хук useMemo React для получения отфильтрованных результатов

 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 ])
 

Теперь вы можете просто использовать filtered вместо data возвращаемого значения

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