Как обновить Event.target после того, как props.function в дочернем компоненте отправляется в redux-thunk onClick

#javascript #reactjs #react-redux

#javascript #reactjs #реагировать-redux

Вопрос:

В этом проекте электронной коммерции onClick «добавить в корзину» должен увеличить количество корзин и изменить текстовое содержимое кнопки на «Удалить из корзины», второй onClick того же элемента должен уменьшить количество и изменить текстовое содержимое обратно на «Добавить в корзину». Я показал 2 разных условных синтаксиса, которые приводят к противоположному поведению.

 function RenderBooks({book, updateCart}) {
    return(
        <Card className="allbooks">
            <CardBody>
            <Link to="/" style={{textDecoration:'none', color:'black'}} >
                <CardTitle><strong>{book.name}</strong></CardTitle>
                <CardImg width="100%" src={bookImg} alt="book image" />
                <CardText>{book.price}</CardText>
            </Link>
                <form>
                    <Button className="add-to-cart" style={{textDecoration:'none'}} color="link" 
                        onClick={(e, id) => updateCart(e, book.id)}
                    >
                        Add to cart
                    </Button>
                </form>
            </CardBody>
        </Card>
    );   
}
  

В первом условии updateCart срабатывает event.target.textContent , но this.props.AddToCart , который вызывает redux dispatch в родительском компоненте, не срабатывает, в то время как в условии else имеет место обратное, то есть срабатывает функция отправки, а event.target — нет. Как я могу заставить функцию отправки запускаться после срабатывания event.target.textContent, заранее спасибо.

 class Books extends React.Component {

    constructor(props){
        super(props);

        this.updateCart = this.updateCart.bind(this);
        
    }
    

    updateCart(event, id) {

        if (event.target.textContent === 'Add to cart') {
            event.target.textContent = 'Remove from cart';
            const count = this.props.cartcount.cartcount;
            () => {
                this.props.addToCart(id, count);
            }
        }
        else {
            event.target.textContent = 'Add to cart';
            let count = this.props.cartcount.cartcount;
            this.props.subtractFromCart(id, count);
        }
    }


    render() {

        const count = this.props.cartcount.cartcount;
        const book = this.props.books.books.map((book, index) => {
            return ( 
                <div key={index} className="col-8 col-md-4 col-lg-3">
                    <RenderBooks book={book} updateCart={this.updateCart} />
                </div>     
            );
        });
        
        return (
            <div>
                <Navbar dark expand="md" id="nav-books">
                    <div className="container">
                        <Nav className="mr-auto" navbar>
                            <NavItem>
                                <NavLink className="nav-link" to='/'>
                                    <BsArrowLeft />
                                </NavLink>
                            </NavItem>
                        </Nav>
                        <NavbarBrand className="mc-auto logo" href="/">Soteria</NavbarBrand>
                        <Nav className="ml-auto" navbar>
                            <NavItem>
                                <NavLink className="nav-link" to='/'>
                                    <FiShoppingCart /> {count}
                                </NavLink>
                            </NavItem>
                        </Nav>
                    </div>
                </Navbar>
                <div className="container books">
                    <div className="row">
                        {book}
                    </div>
                </div>
            </div>
        );
    }   
}

export default Books;
  

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

1. Что вы пытаетесь сделать в методе () => { target; this.props.addToCart(id, count); } updateCart, если это анонимная функция или что? Пожалуйста, уточните!

2. Спасибо @Dolly. Поцарапайте цель; и это все равно не имеет значения, this.props.AddToCart(id, count) отправляется в родительском / главном компоненте в redux-thunk в ActionCreators, который затем отправляется в редуктор, который обновляет count и экспортирует в configureStore. Количество обновляется, но event.textContent = «Удалить из корзины» не обновляется, хотя и обновляется в console.log. Удалите отправку props.function, и event.textContent сработает. Судя по результатам исследований, это похоже на поведение redux-thunk, но не могу сказать наверняка.

3. Привет @Uwem Это должно сработать. Проверьте минимальное воспроизведение, которое я создал в соответствии с вашим сценарием codesandbox.io/s/serene-cookies-8z5y5?file=/index.js

4. Спасибо @Dolly, ваша реализация работает, но мне нужно было добиться такого поведения после отправки props.AddToCart() в redux-thunk, чего не происходит, потому что redux-thunk синхронен, как я узнал, поэтому прослушиватель событий уже отключается к моменту обновления хранилища. Видя event.persist() в вашей реализации, мне интересно, сохранится ли событие до обновления хранилища, но я решил проблему с помощью интуитивно понятного решения, явно обновив пользовательский интерфейс в RenderBooks(), если хранилище обновлено..

5. @Dolly Я опубликую решение. Возможно, я предоставил или не предоставил достаточно контекста, но спасибо за вклад.

Ответ №1:

Я узнал, что redux-thunk является синхронным, поэтому прослушиватель событий теряется к моменту обновления хранилища. Итак, я в конце концов придумал, что такое интуитивно понятное решение с реакцией на сокращение, добавив параметр itemids, массив, в котором хранятся идентификаторы элементов, на которые нажаты, и обновил пользовательский интерфейс в RenderBooks() с помощью троичных операторов;

 function RenderBooks({book, itemids, updateCart}) {
    return(
        <Card>
            <CardBody>
            <Link to="/" style={{textDecoration:'none', color:'black'}} >
                <CardTitle><strong>{book.name}</strong></CardTitle>
                <CardImg width="100%" src={bookImg} alt="book image" />
                <CardText>{book.price}</CardText>
            </Link>
                    {
                        itemids.length != 0 ?
                            itemids.includes(book.id) ?
                                <Button onClick={(e, id) => updateCart(e, book.id)}>
                                    Remove from cart
                                </Button>
                            :
                                <Button onClick={(e, id) => updateCart(e, book.id)}>
                                    Add to cart
                                </Button>
                        :
                        
                        <Button onClick={(e, id) => updateCart(e, book.id)}>
                            Add to cart
                        </Button>       
                    }
            </CardBody>
        </Card>
    );   
}

  

Итак, в updateCart я использую только event.target.textContent, чтобы определить, какую props.function вызывать.

 class Books extends React.Component {

    constructor(props){
        super(props);

        this.updateCart = this.updateCart.bind(this);
    }


    updateCart(event, id) {

        let target = event.target.textContent;

        if (target === 'Add to cart') {
                        
            this.props.addToCart(id)

        }
        else {
            
            this.props.subtractFromCart(id);
        }
    }


    render() {

        const book = this.props.books.books.map((book, index) => {
            return ( 
                <div key={index} className="col-8 col-md-4 col-lg-3">
                    <RenderBooks book={book} itemids={this.props.itemids}       
                                 updateCart={this.updateCart} 
                    />
                </div>     
            );
        });
        
        return (
            <div>                  
                <div className="container books">
                    <div className="row">
                        {book}
                    </div>
                </div>
            </div>
        );
    }   
}
export default Books;