ngrx处理对象中的嵌套数组 [英] ngrx dealing with nested array in object

查看:98
本文介绍了ngrx处理对象中的嵌套数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习redux模式,并使用ngrx与angular 2.我创建了一个具有以下形状的示例博客网站。 data-lang =jsdata-hide =falsedata-console =truedata-babel =false>

 导出接口BlogContent {id:string; header:string;标签:string []; title:string; actualContent:ActualContent [];}  



如下所示:

导入{ActionReducer,Action}



这个工作正常,但我不确定如果它是正确的方法,或者我应该以某种方式将ActualContent分离为它自己的reducer和actions,然后合并它们。
对不起,如果这篇文章不属于这里,你可以指导我在哪里应该把这篇文章,我会从这里删除它。提前致谢。


我做了一些研究,但无法找到任何具有复杂嵌套对象的文章,以便我可以参考。请添加任何有用的博客链接ngrx或相关主题,可以帮助我。

解决方案

而不是嵌套结构

p>

 出口接口BlogContent {
id:string;
header:string;
tags:string [];
title:string;
actualContent:ActualContent []; < ------ NESTED
}

您应该有一个归一化状态。



例如,您应该有以下类似的东西:

  //这应该是你的商店
导出接口BlogContents {
byId:{[key:string]:BlogContent};
allIds:string [];
}

//这是用来输入你会在byId
导出界面中找到的对象的方法BlogContent {
id:string;
// ...
actualContentIds:string [];
}

// ----------------------------------- -----------------------

//这应该到你的商店
导出界面ActualContents {
byId:{[key:string]:ActualContent};
allIds:string [];
}

导出接口ActualContent {
id:string;
// ...
}

因此,如果您尝试填充您的存储它看起来像这样:

  const blogContentsState:BlogContents = {
byId:{
blogContentId0 :{
id:'idBlogContent0',
// ...
actualContentIds:['actualContentId0','actualContentId1','actualContentId2']
}
} ,
allIds:['blogContentId0']
};
$ b $常量actualContentState:ActualContents = {
byId:{
actualContentId0:{
id:'actualContentId0',
// ...
},
actualContentId1:{
id:'actualContentId1',
// ...
},
actualContentId2:{
id:'actualContentId2 ',
// ...
}
},
allIds:['actualContentId0','actualContentId1','actualContentId2']
};

在您的逻辑或视图中(例如Angular),您需要嵌套结构以便迭代在你的数组上,因此,你不想迭代一个字符串数组。相反,您需要 actualContent:ActualContent [];



为此,您创建一个选择。每当您的商店发生变化时,您的选择器就会启动并生成一个新的原始数据视图。

  //假设你可以从你的商店blogContentsState和actualContentsState $ b $ const getBlogContents =(blogContentsState,actualContentsState)=> 
blogContentsState
.allIds
.map(blogContentId =>({
... blogContentsState.byId [blogContentId],

actualContent:blogContentsState
.byId [blogContentId]
.actualContentIds
.map(actualContentId => actualContentsState.byId [actualContentId])
}));

我知道在开始时可以处理很多事情,我邀请您阅读官方文档关于选择器和规范化状态: http://redux.js.org/docs/recipes /reducers/NormalizingStateShape.html



在学习ngrx时,您可能想看看我制作的一个名为Pizza-同步。 代码源位于Github上。这是一个项目,我做了这样的演示:)。 (您还应该安装 ReduxDevTools应用,查看商店情况)。



如果您感兴趣,我只在带有Pizza-Sync的Redux上制作了一个小视频焦点: https://youtu.be/I28m9lwp15Y


I am learning the redux pattern and using ngrx with angular 2. I am creating a sample blog site which has following shape.

export interface BlogContent {
  id: string;
  header: string;
  tags: string[];
  title: string;
  actualContent: ActualContent[];
}

and my reducer and actions are as following:

import { ActionReducer, Action } from '@ngrx/store';
import * as _ from 'lodash';
export interface ActualContent {
  id: string;
  type: string;
  data: string;
}

export interface BlogContent {
  id: string;
  header: string;
  tags: string[];
  title: string;
  actualContent: ActualContent[];
}

export const initialState: BlogContent = {
  id: '',
  header: '',
  tags: [],
  title: '',
  actualContent: [],
};

export const ADD_OPERATION = 'ADD_OPERATION';
export const REMOVE_OPERATION = 'REMOVE_OPERATION';
export const RESET_OPERATION = 'RESET_OPERATION';
export const ADD_IMAGE_ID = 'ADD_IMAGE_ID';
export const ADD_FULL_BLOG = 'ADD_FULL_BLOG';
export const ADD_BLOG_CONTENT_OPERATION = 'ADD_BLOG_CONTENT_OPERATION';
export const ADD_BLOG_TAG_OPERATION = 'ADD_BLOG_TAG_OPERATION';

export const blogContent: ActionReducer<BlogContent> = (state: BlogContent= initialState, action: Action ) => {
    switch (action.type) {
      case  ADD_OPERATION :
        return Object.assign({}, state, action.payload );
      case  ADD_BLOG_CONTENT_OPERATION :
        return Object.assign({}, state, { actualContent: [...state.actualContent, action.payload]});
        case  ADD_BLOG_TAG_OPERATION :
        return Object.assign({}, state, { tags: [...state.tags, action.payload]});
      case REMOVE_OPERATION :
        return Object.assign({}, state, { actualContent: state.actualContent.filter((blog) => blog.id !== action.payload.id) });
      case ADD_IMAGE_ID : {
        let index = _.findIndex(state.actualContent, {id: action.payload.id});
        console.log(index);
        if ( index >= 0 ) {
          return  Object.assign({}, state, {
            actualContent :  [
              ...state.actualContent.slice(0, index),
              action.payload,
              ...state.actualContent.slice(index + 1)
            ]
          });
        }
        return state;
      }
      default :
        return state;
    }
};

and this is working fine but i am not sure if its the right approach or should i somehow separate the ActualContent into its own reducer and actions and then merge them. Sorry if this post does not belong here and you can guide me where should put this post and i will remove it from here. Thanks in advance.

P.S. I have done some research but couldnt find any article that has complex nested objects so that i can refer. Please add any useful blog links of ngrx or related topic which can help me out.

解决方案

Instead of having a nested structure

export interface BlogContent {
  id: string;
  header: string;
  tags: string[];
  title: string;
  actualContent: ActualContent[]; <------ NESTED
}

You should have a normalized state.

For example here you should have something like :

// this should be into your store
export interface BlogContents {
  byId: { [key: string]: BlogContent };
  allIds: string[];
}

// this is made to type the objects you'll find in the byId
export interface BlogContent {
  id: string;
  // ...
  actualContentIds: string[];
}

// ----------------------------------------------------------

// this should be into your store
export interface ActualContents {
  byId: { [key: string]: ActualContent };
  allIds: string[];
}

export interface ActualContent {
  id: string;
  // ...
}

So if you try to populate your store it'd look like that :

const blogContentsState: BlogContents = {
  byId: {
    blogContentId0: {
      id: 'idBlogContent0',
      // ...
      actualContentIds: ['actualContentId0', 'actualContentId1', 'actualContentId2']
    }
  },
  allIds: ['blogContentId0']
};

const actualContentState: ActualContents = {
  byId: {
    actualContentId0: {
      id: 'actualContentId0',
      // ...
    },
    actualContentId1: {
      id: 'actualContentId1',
      // ...
    },
    actualContentId2: {
      id: 'actualContentId2',
      // ...
    }
  },
  allIds: ['actualContentId0', 'actualContentId1', 'actualContentId2']
};

In your logic or view (for example with Angular), you need your nested structure so you can iterate over your array and thus, you don't want to iterate on a string array of IDs. Instead you'd like actualContent: ActualContent[];.

For that, you create a selector. Every time your store change, your selector will kicks in and generate a new "view" of your raw data.

// assuming that you can blogContentsState and actualContentsState from your store
const getBlogContents = (blogContentsState, actualContentsState) =>
  blogContentsState
    .allIds
    .map(blogContentId => ({
      ...blogContentsState.byId[blogContentId],

      actualContent: blogContentsState
        .byId[blogContentId]
        .actualContentIds
        .map(actualContentId => actualContentsState.byId[actualContentId])
    }));

I know it can be a lot to process at the beginning and I invite you to read the official doc about selectors and normalized state : http://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html

As you're learning ngrx, you might want to take a look into a small project I've made called Pizza-Sync. Code source is on Github. It's a project were I've done something like that to demo :). (You should also definitely install the ReduxDevTools app to see how is the store).

I made a small video focus only on Redux with Pizza-Sync if you're interested : https://youtu.be/I28m9lwp15Y

这篇关于ngrx处理对象中的嵌套数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆