首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在嵌套属性上使用createEntityAdapter?

如何在嵌套属性上使用createEntityAdapter?
EN

Stack Overflow用户
提问于 2020-10-08 19:51:51
回答 1查看 3.9K关注 0票数 5

我正在创建一个带有React/Redux的应用程序,并且我对使用React和Redux都很陌生。我被困在想如何构造redux商店。这里简要描述了我正在尝试实现的目标,并使用了图书示例,如redux createEntityAdapter文档中所示。

我有一页书的清单。用户可以点击一本或多本书,每本书都会显示章节的列表。新的或缺失的章节可以在任何时候添加,因为它们在服务器上可用。增加的章节需要以正确的位置添加到列表中。

  • 第一册
    • 第一章
    • 第二章
    • 第三章
    • 第六章

  • 第二册
  • 第3册

图书列表是一个组件,而章节列表是另一个组件,但是由于有很多书,所以会有许多章节列表组件的实例。每个组件都有自己的部分。

这家商店看起来像:

代码语言:javascript
复制
bookList : [ Book1, Book2, Book3, ...]
ChapterList: { 
  Book1 : {
    chapters: [
      { 
         Chapter : 'Chapter1',
         info: 'Chapter info',
         other: 'more stuff'
      },
      { 
         Chapter : 'Chapter2',
         info: 'Chapter info',
         other: 'more stuff'
      },
      {...}
    ],
    bookInfo: 'info about book'
  },
  Book2 : { ... },
  Book3 : { ... }
}

问题是,章节信息正在被流,因此是不断更新和缺失的章节可以随时到达。因此,每次新数据到达时,我都需要对章节数组进行排序,而数组不是很长,按50个元素的顺序排列,新数据每秒到达几次。

我打算使用createEntityAdapter来规范章节数组,但是我看不出这是怎么可能的,因为它是嵌套在Book#属性中的,并且需要Book#属性,因为我使用的是ChapterList组件的多个实例。

代码语言:javascript
复制
const ChapterListAdapter = createEntityAdapter({
  // where bookNum needs to Book1, Book2, Book3 etc... 
  selectId: (chapterList) => chapterList[bookNum].chapters,

  sortComparer: (a, b) => a.chapters.localeCompare(b.chapters
}) 

我该怎么解决这个问题?修改店面?是否有一种方法可以使chapterList变得平坦,使章节处于最高层?我是否将自己的规范化/排序逻辑写入还原器?

EN

回答 1

Stack Overflow用户

发布于 2021-04-23 05:33:23

是否有一种方法可以使chapterList变得平坦,使章节处于最高层?我是否将自己的规范化/排序逻辑写入还原器?

您可以查看正火状态形状上的Redux指南作为起点。

这里有两个实体:“书籍”和“章节”。它们之间有一种关系:每一章都属于一本书,每一本书都包含一个有序的章节列表。你需要两个实体适配器。你可以用一两片--也许两片比较容易,但没关系。

您的规范化状态形状应该如下所示:

代码语言:javascript
复制
{
  books: {
    ids: [1, 2, 3],
    entities: {
      1: {
        id: 1,
        title: "Book 1",
        bookInfo: 'info about book',
        chapterIds: [75, 962, 64], // an ordered array of chapters
      },
      2: { /* ... */ },
      3: { /* ... */ }
    }
  },
  chapters: {
    ids: [64, 75, 962],
    entities: {
      64: {
        id: 64,
        name: "Some Chapter Title",
        info: "",
        other: "",
        bookId: 1 // the id of the book that this chapter belongs to
      },
      75: { /* ... */ },
      962:  { /* ... */ }
    }
  }
}

用TypeScript术语来说:

代码语言:javascript
复制
import { EntityState, EntityId } from "@reduxjs/toolkit";

export interface Book {
  id: EntityId;
  title: string;
  bookInfo: string;
  chapterIds: EntityId[];
}

export interface Chapter {
  id: EntityId;
  name: string;
  info: string,
  other: string;
  bookId: EntityId;
}

interface State {
  books: EntityState<Book>;
  chapters: EntityState<Chapter>;
}

当数据来自服务器时,我很难在不知道数据是什么形状的情况下编写还原器。根据你对一个接一个的章节的看法,听起来好像已经标准化了吗?

对于我来说,编写组件更容易。我们有从id中选择完整实体对象的选择器:

代码语言:javascript
复制
const bookAdapter = createEntityAdapter<Book>();

const chapterAdapter = createEntityAdapter<Chapter>();

export const {
  selectIds: selectBookIds,
  selectById: selectBookById
} = bookAdapter.getSelectors((state: State) => state.books);

export const { 
  selectById: selectChapterById
} = chapterAdapter.getSelectors((state: State) => state.chapters);

因此,每个组件所需要的唯一支柱就是id

代码语言:javascript
复制
const Chapter = ({ id }: { id: EntityId }) => {
  const chapter = useSelector((state) => selectChapterById(state, id));

  // probably some hook here to request the chapter if not loaded
  // dispatch an async thunk inside of a useEffect

  if (!chapter) {
    return <Loading />;
  }

  return (
    <div>
      <h3>{chapter.name}</h3>
      <p>{chapter.info}</p>
    </div>
  );
};

const Book = ({ id }: { id: EntityId }) => {
  const book = useSelector((state) => selectBookById(state, id));

  // probably some hook here to request the book if not loaded
  // dispatch an async thunk inside of a useEffect

  if (!book) {
    return <Loading />;
  }

  return (
    <div>
      <h1>{book.title}</h1>
      <p>{book.bookInfo}</p>
      <h2>Chapters</h2>
      <ul>
        {book.chapterIds.map((chapterId) => (
          <li key={chapterId}>
            <Chapter id={chapterId} />
          </li>
        ))}
      </ul>
    </div>
  );
};

您可以通过看看这个答案获得更多关于如何从API请求实体的信息,只有当实体尚未加载时。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64269690

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档