Redux 내부에 관계형 데이터를 저장하는 방법



사진 제공: Tobias Fischer on Unsplash

조만간 모든 프런트엔드 개발자는 관계형 데이터를 Redux 스토어에 저장해야 합니다.

TL; DR



Firebase의 advice을 따르십시오. 매우 유용합니다.

데이터



관계형 DB를 기반으로 하는지 여부에 관계없이 데이터는 그들 사이에 관계가 있습니다.

우리는 다른 리소스와 관계를 가질 수 있는 모든 유형의 데이터를 리소스로 정의할 것입니다.

예제 리소스는 개인 블로그의 게시물일 수 있습니다.

이 게시물은 작성자와 1:1 관계(게시물 관점에서 볼 때 작성자는 게시물과 1:N 관계가 됨)와 댓글과 1:N 관계가 됩니다.

비효율적인 구조



개인 블로그가 게시물 목록과 게시물 각각에 대한 세부 정보 페이지만 표시해야 한다고 가정해 보겠습니다.

이 특정 예의 경우 Redux 스토어에서 id로 인덱싱된 모든 게시물을 포함하는 첫 번째 수준 키를 가질 수 있습니다. 각각 안에 저자의 데이터와 의견을 내포할 수 있습니다.

const store = {
  posts: {
    'p123': {
      id: 'p123',
      title: 'Best React pattern in the world!',
      author: {
        id: 'a123',
        name: 'Francesco',
        email: '[email protected]',
      },
      comments: {
        'c123': {
          id: 'c123',
          body: 'Best article ever!',
        },
        'c124': {
          id: 'c124',
          body: 'Best article ever ever!',
        },
      }
    },
  }
}

// And so on, you get the point

작성자의 게시물 목록이 포함된 작성자 프로필 페이지를 만들려는 경우 문제가 발생합니다.

Redux 선택자를 예로 들면 다음과 같은 방법으로 필요한 데이터를 검색할 수 있습니다.

// This returns an array of posts
const getPostsByAuthor = authorId => state => (
  Object.values(state.posts).filter(post => post.author.id === authorId)
)

// And you'd call this selector like this:
const state = store.getState()
const postsByAuthor = getPostsByAuthor('a123')(state) // [...]

그러나 우리가 필요한 것을 얻을 수 있는 것은 특히 비효율적일 것입니다. 매번 모든 게시물을 검토해야 합니다.

가중 구조



가중 구조는 관계형 DB 내 가상 테이블의 1:1 표현일 수 있습니다.

const store = {
  posts: {
    'p123': {
      id: 'p123',
      title: 'Best React pattern in the world!',
      author: 'a123',
    },
  },
  author_posts: {
    'a123': ['p123'],
  },
  authors: {
    'a123': {
      id: 'a123',
      name: 'Francesco',
      email: '[email protected]',
    }
  },
  post_comments: {
    'p123': ['c123', 'c124'],
  },
  comments: {
    'c123': {
      id: 'c123',
      body: 'Best article ever!',
      post: 'p123',
    },
    'c124': {
      id: 'c124',
      body: 'Best article ever ever!',
      post: 'p123',
    },
  },
}

이 경우 중첩 문제를 제거했습니다. 그러나 Redux 스토어에 두 개의 새로운 첫 번째 수준 키를 추가했습니다.

이 접근 방식이 완전히 잘못된 것은 아니지만 애플리케이션이 커짐에 따라 모든 관계를 효율적으로 관리하기 어려울 수 있습니다.

리소스의 양이 제한되어 있는 경우 유용한 접근 방식이 될 수 있습니다. 그러나 리소스의 양이 제한되어 있으면 Redux가 실제로 필요하지 않을 수도 있습니다.

효율적인 구조



Firebase의 권장 사항에 따라 몇 가지 첫 번째 수준 키를 저장할 수 있습니다.

const store = {
  posts: {
    data: {
      'p123': {
        id: 'p123',
        title: 'Best React pattern in the world!',
        author: 'a123',
      },
    },
    comments: {
      'p123': ['c123', 'c124'],
    },
  },
  authors: {
    data: {
      'a123': {
        id: 'a123',
        name: 'Francesco',
        email: '[email protected]',
      },
    },
    posts: {
      'a123': ['p123'],
    },
  },
  comments: {
    data: {
      'c123': {
        id: 'c123',
        body: 'Best article ever!',
        post: 'p123',
      },
      'c124': {
        id: 'c124',
        body: 'Best article ever ever!',
        post: 'p123',
      },
    },
  },
}

Firebase와 달리 "자리 표시자"와 관계를 중첩하지 않습니다.

대신 첫 번째 수준 키를 작은 두 번째 수준 저장소 컨테이너로 구성합니다.
reducerscombineReducers 함수에 대해 비슷한 생각을 하고 있습니까? 동일한 논리: 전역 개체를 표현할 수 있는 가장 작은 부분으로 줄입니다.

보너스: 선택자를 구성하는 방법



Redux 스토어를 구성한 후 가장 먼저 떠오를 수 있는 질문은 이 데이터를 어떻게 얻을 수 있습니까?

다음은 간단한 선택자입니다.

// Base data

const selectAuthors = state => Object.values(state.authors.data)
const selectAuthor = id => state => state.authors.data[id]

const selectPosts = state => Object.values(state.posts.data)
const selectPost = id => state => state.posts.data[id]

// Totally useless
const selectComments = state => Object.values(state.comments.data)
// Maybe useless
const selectComment = id => state => state.comments.data[id]

// Relations

const selectAuthorPosts = authorId => state => {
  const authorPosts = state.authors.posts[authorId] || []
  return authorPosts.map(postId => selectPost(postId)(state))
}

const selectPostComments = postId => state => {
  const postComments = state.posts.comments[postId] || []
  return postComments.map(commentId => selectComment(commentId)(state))
}

결론



이제 Redux 저장소를 구성하여 관계형 데이터를 저장할 수 있습니다. 어떤 경우에는 과잉일 수 있지만 더 복잡한 응용 프로그램을 처리하는 데 유용합니다.

게시물이 마음에 드셨다면 🦄를 남겨주세요!

좋은 웹페이지 즐겨찾기