하지만 위 데이터 구조에서 코멘트를 업데이트를 한다고 해보자. 중첩된 데이터구조에서는 리듀서 로직도 중첩될거다. 해당 포스팅들에 대해 반복문을 돌면서, 포스팅의 안의 comments를 또 반복문돌아야한다. 이 방법은 느리고 코드도 더러워지기 쉽다.
또, 코멘트를 여러개 작성한 작성자가 이름을 바꾼다고 해보자. (물론 닉네임 수정은 보통 포스팅 페이지에서 하지 않지만..) SPA에서 수정된 닉네임을 API 요청 후, comments에 있는 닉네임을 수정해야한다. 이 때, 유저 정보가 여러곳(posting객체의 author, comment 객체에서 commenter)에서 관리 되고 있기때문에, 전부 탐색하며 변경해줘야 한다.
이러한 단점들 때문에, 정규화를 한번 해놓으면 위 과정을 거치지 않고 쉽고 빠르고 간단하게 데이터를 관리할 수 있다. 정규화가 뭔지 모르겠다면 아래 정규화 결과를 보자.
Entity의 첫번째 인자는 key인데, 필수값이다. 정규화되고 나서 결과값에서 작성된 key에 정규화된 결과값이 있다. 위에서 보면 entities.users에 정규화된 결과값이 있다는 것을 알 수 있다.
하지만 key에 id값이 들어간걸 볼 수 있는데 어떻게 알까?
normalizr는 데이터에 id 프로퍼티를 가진다면 unique하다고 판단하여 key로 사용한다.
그리고 result는 뭘까?
result는 순서를 유지하기 위해, 기존 데이터의 배열 순서대로 id를 저장한다.
아래에서 자세한 API 번역을 보자.
schema.Entity(key, definition = {}, options = {})
key: require, 결과값에서 해당 키 아래에 모든 엔티티가 정규화된 응답값을 가진다.
definition : 이 entity 내부에서 발견된 중첩된 엔티티 정의. default 값은 빈 객체다. 정규화된 엔티티의 출력값에 모든 값이 카피될 것이다.
options:
idAttribute : 해당 entity 타입의 unique ID, key나 unique id에 해당하는 value를 리턴하는 함수. (기본 값은 'id'다.) 함수에서는 다음 인자를 받는다ㅣ.
value : entity의 input value
parent : input 배열의 부모 객체
key : 부모 객체에서 input 배열이 나타나는
mergeStrategy(entityA, entityB): 동일 id를 갖는 2개의 entity를 머지할 떄 이용하는 전략 함수. 기본적으로 더 최근의 값을 이전값에 머지한다.
processStrategy(value, parent, key): entity 전처리할 때 사용하는 전략 함수. 정규화 하기 전에 데이터를 추가하거나 완전히 entity를 변경하기 위한 메서드로 이용한다. 디폴트로 input entity의 shallow copy를 리턴한다.
instance method
define(definition): 사용할 때, 전달된 definition은 Entity 생성자에 전달된 original definition으로 머지된다. 이 메서드는 스키마에서 순환 참조를 생성할 때 유용하다.
instance attributes
key: 생성자에 제공된 키를 리턴한다.
idAttribute: 생성자에 제공된 idAttribute를 리턴한다.
const data = {
id_str: '123',
url: 'https://twitter.com',
user: { id_str: '456', name: 'Jimmy' }
};
// 서버에서 id로 attribute를 주지 않는 경우 3번째 인자와 같이 id를 알려줄 수 있다.
// 위 데이터에서 user 데이터가 중첩되어있기 때문에, entity type을 하나 더 선언해준다.
const user = new schema.Entity('users', {}, { idAttribute: 'id_str' });
// 한 데이터에서 2가지의 엔티티를 정규화하기 위해 선언한다.
const tweet = new schema.Entity(
'tweets',
// userEntity가 중첩되어있다고 알려준다. 이렇게 하면 twwet, user 엔티티가 최상위 레벨로 정규화된다.
{ user: user },
{
idAttribute: 'id_str',
// Apply everything from entityB over entityA, except for "favorites"
mergeStrategy: (entityA, entityB) => ({
...entityA,
...entityB,
favorites: entityA.favorites
})
// Remove the URL field from the entity
// processStrategy: entity => omit(entity, 'url')
}
);
const normalizedData = normalize(data, tweet);