#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>