В компоненте формы с комментариями такой код
import React, {Component} from 'react';
import ReactHtmlParser from "react-html-parser";
import {validateEmail} from '../../../../helpers/validation';
import Tabs from './Tabs';
import ProductComments from '../ProductComments';
class ProductTabs extends Component {
constructor(props){
super(props);
this.state = {
comments: [],
users: {},
commentsLength: 0,
/* states for creating new comment */
productCommentContent: '',
productSlug: this.props.productSlug,
productID: this.props.productID,
userID: null,
userName: '',
userEmail: '',
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleRemove = this.handleRemove.bind(this);
}
componentDidMount(){
console.log( 'this.props', this.props );
const {productSlug, setProductComments} = this.props;
axios.get(`/api/product-comments/${productSlug}`).then(data => {
setProductComments(data.data);
let {allComments, allUsers} = data.data;
const users = allUsers.reduce((acc, el) => (
acc[el.id] = el, acc
), {});
const USER_ID = this.state.userID ? this.state.userID : 11
this.setState({
comments: allComments,//is Array
users: users,// is Object
userID: USER_ID,
userName: (USER_ID === 11) ? '' : users[USER_ID]['name'],
userEmail: users[USER_ID]['email'],
userLogo: users[USER_ID]['logo'],
commentsLength: allComments.length ? allComments.length : 0,
});
});
}
handleChange(e){
this.setState({
[`${e.target.name}`]: e.target.value,
});
}
handleSubmit(e){
e.preventDefault();
if ( this.state.productCommentContent && validateEmail(this.state.userEmail) && this.state.userName ) {
const productComment = {
content: this.state.productCommentContent,
product_slug: this.state.productSlug,
product_id: this.state.productID,
user_id: this.state.userID,
user_name: this.state.userName,
user_email: this.state.userEmail,
}
axios.post('/api/product-comments', productComment).then(response => {
const newCommentsList = [...this.state.comments, response.data];
this.setState({
comments: newCommentsList,
commentsLength: newCommentsList.length,
});
});
}
}
handleRemove(id){
const {removeProductCommentById} = this.props;
const newCommentsList = this.state.comments.filter(comment => comment.id !== id);
this.setState({
comments: newCommentsList,
commentsLength: newCommentsList.length,
});
removeProductCommentById(id);
}
render(){
const {tabBg, descr, ingredients, usage, title } = this.props;
return (
<Tabs tabBg={tabBg}>
{descr && (
<div title="Описание">
{ReactHtmlParser(descr)}
</div>
)}
{ingredients && (
<div title="Состав">
{ReactHtmlParser(ingredients)}
</div>
)}
{usage && (
<div title="Применение">
{ReactHtmlParser(usage)}
</div>
)}
<div title={`Отзывы (${this.state.commentsLength})`}>
<ProductComments
title={title}
state={this.state}
handleChange={this.handleChange}
handleSubmit={this.handleSubmit}
handleRemove={this.handleRemove}
/>
</div>
</Tabs>
);
}
}
export default ProductTabs;
actions/products.js
import {
SET_PRODUCTS,
SET_PRODUCT_BY_SLUG,
SET_PRODUCT_BY_SLUG_SUCCEEDED,
SET_PRODUCT_BY_SLUG_FAILED,
SET_PRODUCT_COMMENTS,
REMOVE_COMMENT_BY_ID,
REMOVE_COMMENT_BY_ID_SUCCEEDED,
SHOW_ALL,
BESTSELLER,
FACE,
BODY,
SCRUB
} from './types';
export const setProducts = products => ({
type: SET_PRODUCTS,
payload: products
});
export const setProductComments = comments => ({
type: SET_PRODUCT_COMMENTS,
payload: comments
});
export const removeProductCommentById = id => {
return async dispatch => {
axios.delete(`/api/product-comments/${id}`).then(() => {
dispatch({ type: REMOVE_COMMENT_BY_ID, payload: id });
});
};
};
export const setProductBySlug = slug => {
return async dispatch => {
dispatch({ type: SET_PRODUCT_BY_SLUG });
axios.get(`/api/products/${slug}`)
.then(({data}) => {
if(data.product){
dispatch({ type: SET_PRODUCT_BY_SLUG_SUCCEEDED, payload: data });
} else {
dispatch({ type: SET_PRODUCT_BY_SLUG_FAILED, payload: 404 });
}
}).catch(err => {
dispatch({ type: SET_PRODUCT_BY_SLUG_FAILED, payload: err });
});
};
}
export const CategoryFilters = {
SHOW_ALL: SHOW_ALL,
BESTSELLER: BESTSELLER,
FACE: FACE,
BODY: BODY,
SCRUB: SCRUB,
};
reducers/products.js
import {
SET_PRODUCTS,
SET_PRODUCT_BY_SLUG,
SET_PRODUCT_BY_SLUG_SUCCEEDED,
SET_PRODUCT_BY_SLUG_FAILED,
SET_PRODUCT_COMMENTS,
REMOVE_COMMENT_BY_ID,
} from '../actions/types';
const INITIAL_STATE = {
isReady: false,
isSingleReady: false,
isSingleLoading: false,
isCommentsReady: false,
items: [],
product: {},
comments: [],
error: null,
};
export default function (state = INITIAL_STATE,action){
switch (action.type) {
case SET_PRODUCTS:
return {
...state,
items: action.payload,
isReady: true
};
case SET_PRODUCT_BY_SLUG:
return {
...state,
isSingleReady: false,
isSingleLoading: true,
error: null,
};
case SET_PRODUCT_BY_SLUG_SUCCEEDED:
return {
...state,
product: action.payload,
isSingleReady: true,
isSingleLoading: false,
error: null,
};
case SET_PRODUCT_BY_SLUG_FAILED:
return {
...state,
isSingleReady: false,
isSingleLoading: false,
error: action.payload,
};
case SET_PRODUCT_COMMENTS:
return {
...state,
comments: action.payload,
isCommentsReady: true,
};
case REMOVE_COMMENT_BY_ID:
return {
...state,
allComments: state.comments.allComments.filter(comment => comment.id != action.payload),
};
default:
return state;
}
}
Вопрос в том что при удалении комментария я сначала фильтрую состояние компонента а потом через
removeProductCommentById(id);
меняю store. Так правильно делать либо все должно меняться через store?
PS При изменении состояния с помощью setState() происходит ререндер компонента, а происходит ли ререндер при изменении состояния в store ?
Спасибо.