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