Так что я работаю над тем, чтобы добавить объявление в интернет-магазин. Концепция Когда пользователь хочет сохранить листинг, он просто нажимает на значок сердца, и он превращается из серого в черный для этого конкретного элемента.
Я попытался сделать значок сердцакак отдельный компонент, он довольно хорошо взаимодействует с бэкэндом, но когда я пытаюсь сохранить один список, все списки становятся черными.
Сохранить значок компонента
import React from "react";
import { connect } from "react-redux";
import { withRouter } from "react-router";
import { Icon } from "antd";
import PropTypes from "prop-types";
import { Link } from "react-router-dom";
import { fetchSave, fetchSaves, saveListing } from "../../redux/actions/saves";
import authHelper from "../../helpers/auth";
import { toast } from "react-toastify";
class Save extends React.Component {
componentDidMount() {
if (authHelper()) {
const { fetchSave, product } = this.props;
fetchSave(product);
} else {
return null;
}
}
handleSaveListing = () => {
if (authHelper()) {
const { saveListing, product } = this.props;
saveListing(product);
fetchSave(product);
} else {
toast.warn("Please login to save product");
}
};
render() {
const { saved, save, product } = this.props;
return (
<Link className="has-text-right hover-effect" onClick={this.handleSaveListing}>
<Icon
type="heart"
style={{
fontSize: "25px",
padding: "5px",
marginLeft: "55%",
color: `${saved ? "#000000" : "#ebeaea"}`
}}
/>
</Link>
);
}
}
Save.propTypes = {
saved: PropTypes.bool,
save: PropTypes.object
};
Save.defaultProps = {
saved: false,
save: {}
};
const mapStateToProps = state => ({
saved: state.saves.saved,
save: state.saves.save
});
export default withRouter(
connect(
mapStateToProps,
{ fetchSave, saveListing }
)(Save)
);
Один компонент списка
import React from "react";
import { Divider, Icon } from "antd";
import { Link } from "react-router-dom";
import moment from "moment";
import momentTimeZone from "moment-timezone";
import amountFormatter from "../../../helpers/amountFormatter";
import SaveIcon from "../../containers/Save";
const Product = ({ product, handleAddToCart }) => (
<section className="column is-full-mobile is-two-thirds-tablet is-half-desktop is-one-quarter-widescreen is-one-quarter-fullhd">
<div className="card">
<div className="card-image">
<figure className="image is-3by2">
<img src={product.images[0]} alt={product.name} />
</figure>
</div>
<div className="card-content">
<div className="media-content">
<Link to={`/products/${product._id}`} className="title is-5">
{product.name}
</Link>
</div>
<div className="media-content">
Ksh. {amountFormatter(product.amount)}
</div>
<Divider />
<span className="subtitle is-7">
{moment(
momentTimeZone.tz(product.createdAt, "Africa/Nairobi"),
"YYYYMMDD"
).fromNow()}
</span>
<SaveIcon product={product._id} />
</div>
</div>
</section>
);
export default Product;
Сохранение редукционных действий
import { toast } from "react-toastify";
import axios from "axios";
import { LOADING, FETCH_SAVE, FETCH_SAVES, ERROR, SAVE_LISTING } from "../type";
const API = process.env.REACT_APP_API;
export const fetchSaves = () => async dispatch => {
dispatch({
type: LOADING
})
axios
.get(`${API}/saves`)
.then(res => {
dispatch({
type: FETCH_SAVES,
payload: res.data
})
})
.catch(err => {
dispatch({
type: ERROR,
payload: err.response.data
})
toast.error(err.response.data.message)
})
}
export const fetchSave = productId => async dispatch => {
axios
.get(`${API}/save/${productId}`)
.then(res => {
dispatch({
type: FETCH_SAVE,
payload: res.data
})
})
.catch(err => {
dispatch({
type: ERROR,
payload: err.response.data
})
})
}
export const saveListing = product => async dispatch => {
axios
.post(`${API}/saves`, { product })
.then(res => {
dispatch({
type: SAVE_LISTING,
payload: res.data
})
toast.success(res.data.message)
})
.catch(err => {
dispatch({
type: ERROR,
payload: err.response.data
})
toast.error(err.response.data.message)
})
}
Сохранение редуктора
import { LOADING, FETCH_SAVES, FETCH_SAVE, SAVE_LISTING } from "../../actions/type";
let initialState = {
isLoading: false
}
const saveReducer = (state = initialState, action) => {
switch(action.type) {
case LOADING:
return {
...state,
isLoading: true
}
case FETCH_SAVES:
return {
...state,
saves: action.payload.saves,
isLoading: false
}
case FETCH_SAVE:
return {
...state,
saved: action.payload.saved,
isLoading: false,
save: action.payload.save
}
case SAVE_LISTING:
return {
...state,
saved: action.payload.saved,
save: action.payload.save
}
default:
return{
...state
}
}
}
export default saveReducer;
Я ожидаю, что при нажатии на один листинг на значке сердца толькосписок должен стать черным