javascript - ngrx处理对象中的嵌套数组

标签 javascript functional-programming redux ngrx

我正在学习 redux 模式并使用带 Angular 2 的 ngrx。我正在创建一个具有以下形状的示例博客网站。

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

我的 reducer 和 action 如下:

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

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

附言我做了一些研究,但找不到任何有复杂嵌套对象的文章,所以我可以引用。请添加 ngrx 或相关主题的任何有用的博客链接,这可以帮助我。

最佳答案

而不是嵌套结构

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

你应该有一个标准化的状态。

例如这里你应该有这样的东西:

// 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;
  // ...
}

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

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']
};

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

为此,您创建了一个选择器。每次您的商店发生变化时,您的选择器都会启动并生成原始数据的新“ View ”。

// 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])
    }));

我知道一开始可能需要处理很多事情,我邀请您阅读 official doc about selectors and normalized state

在学习 ngrx 时,您可能想看一下我制作的一个名为 Pizza-Sync 的小项目。 Code source is on Github .这是一个项目,我已经做了类似的事情来演示 :)。 (你也一定要安装 ReduxDevTools app 看看商店怎么样)。

如果您有兴趣,我制作了一个小视频,只关注 Redux with Pizza-Sync:https://youtu.be/I28m9lwp15Y

关于javascript - ngrx处理对象中的嵌套数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43667853/

相关文章:

java - 为什么更改总和顺序会返回不同的结果?

haskell - (>>=) 和 (>=>) 之间的区别

javascript - 可变 reducer 的 Redux 初始状态

javascript - Redux- mapStateToProps 不工作

javascript - 将参数从根 saga 传递到分派(dispatch)的操作

javascript - JavaScript 多行注释中的 '@' 符号有什么作用?

javascript - Q :span automaticlly changes its shape when it animates to the border of its parent

javascript - 无法将 Cordova 插件添加到我的 PhoneGap 项目

c# - 在 C# 中生成函数的最佳生成函数的方法

haskell - 在非功能性项目中集成 Haskell