#reactjs #react-hooks #react-props
#reactjs #реагирующие хуки #реагировать-реквизит
Вопрос:
Я работаю над приложением списка контактов. В основном используется список материалов-пользовательский интерфейс из нескольких человек / лиц. Вот примерный план :
PersonListItem — Дочерний компонент: содержит все сведения о персонаже, отображаемые в списке персоналий карточки — Родительский компонент: в основном отображает всех людей и отображает все карточки в виде списка
Недавно я добавил компонент звезды к каждой карточке, идея заключается в том, что если я хочу пометить человека как избранного, я бы щелкнул звездочку, и она стала желтой.
Для достижения этой цели я изучил и внедрил шаблон React lift-state-up with hooks. Итак, теперь поток выглядит так:
Child Component => onClick = {someMethod} => someMethod passed as props to Parent => Parent updates prop component => Child re-renders the component
Но теперь, когда я нажимаю на звездочку любого отдельного контакта, чтобы отметить избранное, все контакты помечаются как избранные.
Я думал использовать event.target для получения идентификатора отдельной звезды, но как мне передать и получить доступ к event.target.id в реквизите ?
Вот мой текущий код:
const PersonListItem = (props) {
const{person, onSelectChanged, favorite, FavColorColor, markFavorite} = props;
return(
<ListItem button
gender = {undefined}
onClick = {onSelectChanged}
<Avatar className = {classes.avatar} src={person.imageLocation === NO_USER_IMAGE : null : person.imageLocation}>
<IconButton StarOutLinedIcon onClick = {markFavorite} style={{backgroundColor: `${FavColor}`}/>
<ListItemText primary =
{
{person.name}
}
secondary = {<div className={classes.smallText}>{person.company}{person.jobTitle}</div>/>
</ListItem>
)
}
export default PersonListItem;
const PersonList = (props) => {
const[favorite, setFavorite] = useState(0);
const[FavColor, setColor] = useState(' ');
const markFavorite = (value) => {
setFavorite(value = !value);
{!favorite ? setColor("yellow") : setColor(" ")}
}
return(
<div className={classes.root}>
<MuiList className={props.className} isLoading={isLoading}>
{
!isLoading amp;amp; person
.map((person, index) => {
return <PersonListItem key={index}
person = {person}
onSelectChanged = () =>{
HideAdd();
}
markFavorite = {markFavorite} FavColorColor = {FavColor}/>
}
}
</MuiList>
</div>
)
}
export default PersonList;
//Material UI ListItem
classs MuiList extends React.Component{
componentDidMount() {
i(this.props.fetch)
{
this.props.fetch();
}
}
render() {
const attributes = {...this.props};
delete attributes.isLoading;
delete attributes.fetch;
delete attributes.fetchData;
const items = this.props.isLoading;
? <ListItem key={0}>
<CircularProgress/>
<ListItemText primary='Loading...'/>
</ListItem>
: this.props.children;
return <List {...attributes>{items}</List>
}
}
export default MuiList;
Ответ №1:
Я бы заменил любимое состояние для объекта идентификаторами пользователей, которые будут отображаться, если они истинны или ложны. также удалите favColor
состояние. это производное состояние от избранного, вам не нужно это состояние.
теперь я бы изменил функцию markFavorite (возможно, изменил имя на toggleFavorite
). он получит идентификатор от этого человека. он проверяет, включено ли оно favorites
; если оно не определено, то ключ еще не существует, поэтому он помечен как избранный), в противном случае только переключите его значение:
const[favorites, setFavorites] = useState({});
const markFavorite = (id) => {
setFavorites(prevFavorites => {
const favorites = { ...prevFavorites }
favorites[id] = favorites[id] === undefined || !favorites[id]
return favorites
})
}
затем при отображении вашего person я бы передал markFavorite
как передачу функции со стрелкой person.id
(здесь я предполагаю, что у person есть идентификатор, это лучше, чем передача индекса с вашей карты).
также передайте isFavorite
с логическим значением favorites[person.id]
( !!
возвращает логическое значение. на самом деле это не обязательно !!
, поскольку undefined
разрешает значение false, это больше для типа согласованности)
markFavorite={() => markFavorite(person.id)} isFavorite={!!favorites[person.id]}/>
по вашему PersonListItem
вам нужно будет изменить определение стиля IconButton на троичное условие:
<IconButton StarOutLinedIcon onClick = {markFavorite} style={{backgroundColor: isFavorite ? 'yellow' : '' }}/>
таким образом, каждый пользователь может быть отмечен независимо, не затрагивая других.
Комментарии:
1. Большое вам спасибо за такое подробное объяснение. Все еще пытаюсь улучшить / изучить React, поэтому, пожалуйста, поделитесь со мной. Несколько вопросов: 1) Откуда берутся преимущества? (Оно нигде не было объявлено) 2) Как работает оператор распространения (… prevFavorites) / переключает значения? Насколько я понимаю, оператор распространения предоставляет доступ только к отдельным элементам внутри объекта.
2. На самом деле, setState может принимать функцию, где ее параметром является состояние. prevFavorites — это состояние, передаваемое функции как параметр (вы можете назвать его так, как хотите). Я использую оператор распространения для создания копии из prevFavorites, чтобы избежать изменения самих prevFavorites.