Proper redux store shape

时间:2017-11-08 22:10:26

标签: reactjs redux react-redux

What is the recommended way to handle this sort of store in redux? I can see a couple different options but am looking to evaluate the tradeoffs of each and see what is the more idiomatic approach.

These are the base models, think of a blog:

  • Post
  • Author
  • Comment

Let's say I have these pages:

  1. View a paginated list of posts: /posts
  2. View one post: /posts/:id
  3. View author profile: /authors/:id

When I go to Page 1 I will fetch a list of posts from the server, ultimately, when I get this data from the server, and the reducers handle it, the store will look like this:

{
  posts: {
    byId: {
      'post-id-1': {
        title: 'Post 1', authorId: 'author-id-1'
      },
      'post-id-2': {
        title: 'Post 2', authorId: 'author-id-2'
      },
    allIds: ['post-id-1', 'post-id-2']
  },
  authors: {
    byId: {
      'author-id-1': {
        name: 'Author 1'
      },
      'author-id-2': {
        name: 'Author 2'
      },
    allIds: ['author-id-1', 'author-id-2']
  }
}

Now I can render the post title with the author's name. Now when a user clicks on a specific post they are going to go to Page 2 (/posts/:id). When they do this, how should this be handled:

Option 1 Reset the store posts when they leave the page, so the store "posts" and "authors" will be empty, and when Page 2 componentDidMount() fires then make another network request to download the post content + the author details for only that one post. If so, now the store will look like:

// when the user navigates away from `/posts`
{
  posts: { byId: {}, allIds: []}
  authors: { byId: {}, allIds: []}
}

// when the user loads `/posts/:id`
{
  posts: {
    byId: {
      'post-id-1': {
        title: 'Post 1', authorId: 'author-id-1'
      },
    allIds: ['post-id-1']
  },
  authors: {
    byId: {
      'author-id-1': {
        name: 'Author 1'
      }
    allIds: ['author-id-1']
  }
}

Option 2 Alternatively, should I keep the data in the store that I already have and do something like this:

// when componentDidLoad() for `/posts/1`

componentDidMount () {
  // check the `store` to see if we already have this post loaded
  // if we do, then do nothing
  // if we do not, then fetch it from the server
  if (this.props.getPostForId(1)) {

  } else {
    this.props.fetchPost({postId: 1})
  }
}

Next, if the user clicks into an author's profile page /authors/1, and I want to fetch the posts that author has written. How does this make my store look? Following Option 1, I can clear out the posts store again before the user navigates, and then on the author's page I can fetch all the posts that author wrote so I can render them on the author's page. But if I do not clear out the full list of posts, and now I fetch the posts that only this author wrote (post 3, post 4, post 5, post 6, etc.), so I keep the posts I already have in the store and merge the results?

{
  posts: {
    'post-id-1': {
      title: 'Post 1', authorId: 'author-id-1'
    },
    'post-id-2': {
      title: 'Post 2', authorId: 'author-id-2'
    },
    'post-id-3': {
      title: 'Post 3', authorId: 'author-id-1'
    },
    'post-id-4': {
      title: 'Post 4', authorId: 'author-id-1'
    },
  },
  authors: {
    byId: {
      'author-id-1': {
        name: 'Author 1'
      },
      'author-id-2': {
        name: 'Author 2'
      },
    allIds: ['author-id-1', 'author-id-2']
  }
}

My main confusion is around how data in the store is shared between pages (components).

  1. When loading one page, how do I know if I already have the data in the store that I need, or if I need to make a request to get it?
  2. When do I clear out old data from the store? Do I ever do this? Should every component be responsible for both dispatching an action to load the data that it needs on mount? And also dispatching an action to remove that data on un-mount?

0 个答案:

没有答案