Как я могу передать событие самой функции, передаваемой в качестве реквизита

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