React/Flux 应用数据结构

React/Flux app data structure

我正在构建一个 Gmail-like 电子邮件浏览器客户端应用程序原型,我需要一些 help/advice 来构建我的 React/Flux 应用程序。我决定使用纯 Flux 来更好地了解它的工作原理。

这是一个简单的电子邮件客户端,带有一个字母列表,按文件夹和标签分组,并且能够将字母添加到收藏夹。

所以,我有一个包含字母数组的 LettersStore。单个字母数据 object 看起来像这样

{
  id: 0,
  new: true, //unread
  checked: false, 
  starred: false, 
  folder: "inbox", //could be 'sent', 'spam', 'drafts'
  sender: "Sender Name",
  subject: "Re:",
  snippet: "Hello there, how are you...",
  body: "Hello there, how are you doing, Mike?",
  date: "02.19.2016 16:30",
  tags:["personal", "urgent"]
}

所以我想要实现的是让用户浏览文件夹(收件箱、已发送、草稿、垃圾邮件)和过滤器(加星标、标签等)

在文件夹和过滤器中,必须有一种方法来 select(检查)some/all 个字母。视图状态取决于 selected 的字母数量(Select-all 复选框更新,就像在 Gmail 上一样)。当用户 select 发送一封信时,将触发 Flux 操作并更新应用程序的状态。

应用程序顶部的 controller-view 执行对 LettersStore public 方法的所有调用并将数据作为道具向下传递,但我不确定,什么 public LettersStore 应该有的方法。目前它有:

emitChange()
addChangeListener()
removeChangeListener()

getAll() //returns array
areSomeLettersInFolderChecked(folderName) //returns bool
areAllLettersInFolderChecked(folderName) //returns bool

countNewLettersInAllFolders() //returns object

这适用于文件夹,但是当涉及到过滤器时,它就不再有意义了,因为加星号的字母在某个文件夹中,我觉得添加像 areSomeLettersInFilterChecked 这样的特定方法是不正确的(filterType) 等

此外,就像在 Gmail 中一样,必须有一种方法可以在属于 "Inbox" 文件夹的 "Starred" 过滤器中找到 select 信件,然后导航至 "Inbox" 文件夹并保留该字母 selected.

也许我应该将 areSomeLettersInFolderChecked-like 内容移动到组件级别?

我确定这一定是一种正确的方法。提前致谢!

与其尝试将所有可能的状态和过滤器封装到您的字母对象中,不如让它保持愚蠢。对其进行规范化,并使用支持的数据结构来表示其他特征。

我将其简化为以下属性:

{
  id: 0,
  sender: "Sender Name",
  subject: "Re:",
  snippet: "Hello there, how are you...",
  body: "Hello there, how are you doing, Mike?",
  date: "02.19.2016 16:30",
  tags:["personal", "urgent"]
}

您的 LetterStore 可以保持不变,或者您可以使用对象或映射来存储字母与它们的 ID 的关系,以便稍后快速查找。

现在我们需要表示我们从消息中删除的属性。

我们可以使用单个 sets 来确定一条消息是否属于 newcheckedstarred 类别。

例如,要给消息加注星标,只需将其 id 添加到 starred 集。

var starred = new Set();
starred.add(message.id);

稍后您可以轻松查看消息是否已加星标。

function isStarred(message) {
  return starred.has(message.id);
}

checkedunread 的模式相同。

要表示文件夹,您可能希望结合使用对象和集合。

var folders = {
  inbox: new Set(),
  sent: new Set(),
  spam: new Set(),
  drafts: new Set()
}

将您的结构简化为这些集合使得设计查询变得非常容易。以下是您谈到的用集合实现的方法的一些示例。

function checkAll() {
  messages.forEach(function(message) {
    checked.add(message.id);
  });
  return checked;
}

function isChecked(message) {
  return checked.has(message.id);
}

function inFolder(name, message) {
  return folders[name].has(message.id);
}

// is message checked and in inbox
if(isChecked(message) && inFolder('inbox', message)) {
  // do something
}

构造复杂的查询变得容易,只需检查消息是否属于多个集合。