在减速器中返回嵌套对象内的状态的更好方法 [英] better way to return states within nested objects in a reducer
问题描述
我正在从后端检索数据,数据结构是这样的.
数据结构
<代码>{身份证":154,"image_title": "iiisdd","img_url": "*********","created_at": "2019-07-18T19:44:49.805Z","updated_at": "2019-07-18T19:44:49.805Z",用户 ID":1,用户":{身份证":1,googleId":空,用户名": "*******,"密码": "$********","email": "e*******","created_at": "2019-06-23T18:57:17.253Z","updated_at": "2019-06-23T18:57:17.253Z"},注释": [{身份证":51,"comment_body": "猫头鹰的生活","created_at": "2019-07-18T20:04:51.484Z","updated_at": "2019-07-18T20:04:51.484Z","user_id": 8,image_id":154,用户":{身份证":8,googleId":空,"用户名": "客人","密码": "********你","email": "*****米","created_at": "2019-07-18T20:04:34.315Z","updated_at": "2019-07-18T20:04:34.315Z"}},{身份证":52,"comment_body": "爸爸","created_at": "2019-07-19T20:16:40.103Z","updated_at": "2019-07-19T20:16:40.103Z",用户 ID":1,image_id":154,用户":{身份证":1,googleId":空,用户名": "*******",密码": "*********","email": "el***********","created_at": "2019-06-23T18:57:17.253Z","updated_at": "2019-06-23T18:57:17.253Z"}},{身份证":53,"comment_body": "测试","created_at": "2019-07-21T22:12:44.729Z","updated_at": "2019-07-21T22:12:44.729Z",用户 ID":1,image_id":154,用户":{身份证":1,googleId":空,用户名": "********",密码": "*********","email": "el********","created_at": "2019-06-23T18:57:17.253Z","updated_at": "2019-06-23T18:57:17.253Z"}}],喜欢":[{身份证":24,"user_id": 2,image_id":154,"created_at": "2019-07-22T19:26:27.034Z","deleted_at": "2019-07-22T19:26:27.034Z","restored_at": "2019-07-22T19:26:27.034Z","updated_at": "2019-07-22T19:26:27.034Z"},{身份证":141,用户 ID":1,image_id":154,"created_at": "2019-07-23T19:57:08.178Z","deleted_at": "2019-07-23T19:57:08.178Z","restored_at": "2019-07-23T19:57:08.178Z","updated_at": "2019-07-23T19:57:08.178Z"}]}
我不认为我在减速器中非常有效地传递数据.有什么更好的方法来重构这段代码,以便我可以轻松地将数据映射到组件/用户界面上.
无需做{this.props.image.images.comments}
或{this.props.images.likes}
等
我想实现这个reducer示例
https://github.com/hibiken/hackafy/blob/master/src/reducers/posts.js
但不确定我是否真的需要.
减速器
import {上传图片成功,POST_COMMENT_SUCCESS,DELETE_IMAGE_FAILURE,FETCH_IMAGES_SUCCESS,DISLIKE_POST_SUCCESS,发表评论,POST_LIKE,POST_LIKE_SUCCESS,POST_LIKE_FAILURE,DELETE_IMAGE_SUCCESS,} 来自'../actions/types';常量初始状态 = {图片: [],喜欢的用户:假,};导出默认值(状态 = 初始状态,动作)=>{开关(动作.类型){案例 FETCH_IMAGES_SUCCESS:返回 {...状态,图像:action.images,};案例 UPLOAD_IMAGE_SUCCESS:const newImage = action.data;返回 {图片: [{id: newImage[0].id,用户:{用户名:newImage[0].user.username,},注释: {comment_body:newImage[0].comments.comment_body,},image_title: newImage[0].image_title,img_url: newImage[0].img_url,},...state.images,//传递之前的图像,],};案例 DELETE_IMAGE_SUCCESS://控制台日志(动作)返回 {...状态,图像:state.images.filter(img => img.id !== action.data),};案例 DELETE_IMAGE_FAILURE:返回 {...状态,错误:action.error,};案例 POST_LIKE:控制台日志(动作);返回 {...状态,};案例 POST_LIKE_SUCCESS:控制台日志(操作数据);const newState = { ...state };//这里我试图浅复制现有的状态;const existingLikesOfPost = newState.images.find(image => image.id === action.data).likes;控制台日志(现有的喜欢的帖子)newState.images.find(image => image.id === action.data).likes = [...existingLikesOfPost, action.newLikeObject];//使用这种方法我得到了一些代码重复,所以我建议使用数组的 **push** 方法的第一种方法.返回新状态;案例 DISLIKE_POST_SUCCESS://....案例 POST_COMMENT:返回 {...状态,};案例 POST_COMMENT_SUCCESS://向帖子添加评论而无需重新渲染.//console.log(action.data.commentBody);返回 {...状态,图像: state.images.map((image) => {//在图像 redux 状态中附加新注释.仅当 image.id === action.idif (image.id === action.id) {返回 {...图像,注释: [...图片评论,{comment_body: action.data[0].comment_body,用户:{用户名:action.data[0].user.username,},},],};}返回图像;}),};默认:返回状态;}};
您应该按照 redux 文档.关键点:
- 你应该让你的商店尽可能平坦
- 尽量减少重复信息=>只设置ids引用而不是实际数据
不要使用数组来存储您的数据,因为您将不得不大量使用查找或过滤器,而是使用带有键的映射/对象作为实际对象的访问点,如下所示:>
comments: {comment_id1: {title: 'title', author:'author_id'}}
要获取所有评论,请添加一个 allComments 数组,其中仅包含这样的 id
allComments: ['comment_id1']
您应该为每个数据子集使用一个新的 reducer.如果您有更多问题,请告诉我或阅读文档.
I'm retrieving data from a backend, the data structure is like this.
Data Strucuture
{
"id": 154,
"image_title": "iiisdd",
"img_url": "*********",
"created_at": "2019-07-18T19:44:49.805Z",
"updated_at": "2019-07-18T19:44:49.805Z",
"user_id": 1,
"user": {
"id": 1,
"googleId": null,
"username": "*******,
"password": "$********",
"email": "e*******",
"created_at": "2019-06-23T18:57:17.253Z",
"updated_at": "2019-06-23T18:57:17.253Z"
},
"comments": [
{
"id": 51,
"comment_body": "owls life",
"created_at": "2019-07-18T20:04:51.484Z",
"updated_at": "2019-07-18T20:04:51.484Z",
"user_id": 8,
"image_id": 154,
"user": {
"id": 8,
"googleId": null,
"username": "guest",
"password": "********u",
"email": "*******m",
"created_at": "2019-07-18T20:04:34.315Z",
"updated_at": "2019-07-18T20:04:34.315Z"
}
},
{
"id": 52,
"comment_body": "dadad",
"created_at": "2019-07-19T20:16:40.103Z",
"updated_at": "2019-07-19T20:16:40.103Z",
"user_id": 1,
"image_id": 154,
"user": {
"id": 1,
"googleId": null,
"username": "*******",
"password": "*********",
"email": "el***********",
"created_at": "2019-06-23T18:57:17.253Z",
"updated_at": "2019-06-23T18:57:17.253Z"
}
},
{
"id": 53,
"comment_body": "test",
"created_at": "2019-07-21T22:12:44.729Z",
"updated_at": "2019-07-21T22:12:44.729Z",
"user_id": 1,
"image_id": 154,
"user": {
"id": 1,
"googleId": null,
"username": "********",
"password": "*********",
"email": "el********",
"created_at": "2019-06-23T18:57:17.253Z",
"updated_at": "2019-06-23T18:57:17.253Z"
}
}
],
"likes": [
{
"id": 24,
"user_id": 2,
"image_id": 154,
"created_at": "2019-07-22T19:26:27.034Z",
"deleted_at": "2019-07-22T19:26:27.034Z",
"restored_at": "2019-07-22T19:26:27.034Z",
"updated_at": "2019-07-22T19:26:27.034Z"
},
{
"id": 141,
"user_id": 1,
"image_id": 154,
"created_at": "2019-07-23T19:57:08.178Z",
"deleted_at": "2019-07-23T19:57:08.178Z",
"restored_at": "2019-07-23T19:57:08.178Z",
"updated_at": "2019-07-23T19:57:08.178Z"
}
]
}
I don't think im passing the data in reducer quite efficiently. What is a better way to refactor this code so that i can easily map the data on the component/ui.
Without having to do {this.props.image.images.comments}
or {this.props.images.likes}
etc.
I want to implement this reducer example
https://github.com/hibiken/hackafy/blob/master/src/reducers/posts.js
but unsure if i really need too.
Reducer
import {
UPLOAD_IMAGE_SUCCESS,
POST_COMMENT_SUCCESS,
DELETE_IMAGE_FAILURE,
FETCH_IMAGES_SUCCESS,
DISLIKE_POST_SUCCESS,
POST_COMMENT,
POST_LIKE,
POST_LIKE_SUCCESS,
POST_LIKE_FAILURE,
DELETE_IMAGE_SUCCESS,
} from '../actions/types';
const initialState = {
images: [],
likedByuser: false,
};
export default (state = initialState, action) => {
switch (action.type) {
case FETCH_IMAGES_SUCCESS:
return {
...state,
images: action.images,
};
case UPLOAD_IMAGE_SUCCESS:
const newImage = action.data;
return {
images: [
{
id: newImage[0].id,
user: {
username: newImage[0].user.username,
},
comments: {
comment_body: newImage[0].comments.comment_body,
},
image_title: newImage[0].image_title,
img_url: newImage[0].img_url,
},
...state.images, // pass the previous images,
],
};
case DELETE_IMAGE_SUCCESS:
// console.log(action)
return {
...state,
images: state.images.filter(img => img.id !== action.data),
};
case DELETE_IMAGE_FAILURE:
return {
...state,
error: action.error,
};
case POST_LIKE:
console.log(action);
return {
...state,
};
case POST_LIKE_SUCCESS:
console.log(action.data);
const newState = { ...state }; // here I am trying to shallow copy the existing state;
const existingLikesOfPost = newState.images.find(image => image.id === action.data).likes;
console.log(existingLikesOfPost)
newState.images.find(image => image.id === action.data).likes = [...existingLikesOfPost, action.newLikeObject]; // using this approach I got some code duplication so I suggested the first approach of using **push** method of array.
return newState;
case DISLIKE_POST_SUCCESS:
// ....
case POST_COMMENT:
return {
...state,
};
case POST_COMMENT_SUCCESS:
// adds a comment to a post without having to re render.
// console.log(action.data.commentBody);
return {
...state,
images: state.images.map((image) => {
// appends new comment withing images redux state. only if image.id === action.id
if (image.id === action.id) {
return {
...image,
comments: [
...image.comments,
{
comment_body: action.data[0].comment_body,
user: {
username: action.data[0].user.username,
},
},
],
};
}
return image;
}),
};
default:
return state;
}
};
You should normalize your state as explained in the redux docs. The key points:
- You should keep your store as flat as possible
- Try to reduce duplicate information => only set ids references instead of actual data
don't use arrays to store your data, because you will have to use find or filter a lot, instead use a map/object with the key as the access point to the actual object like this:
comments: {comment_id1: {title: 'title', author:'author_id'}}
to get all comments, add a allComments array with only the ids like this
allComments: ['comment_id1']
You should use a new reducer for each of these subsets of data. If you have more questions, let me know or read the docs.
这篇关于在减速器中返回嵌套对象内的状态的更好方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!