Redux нормализованные данные с использованием отдельных редукторов - PullRequest
0 голосов
/ 13 декабря 2018

У меня есть модель Posts , в которой есть Пользователь и Комментарии Из чтения документов в формате Redx я узнал, что идеальное состояние нормализовано, и используя такие ключи, какэто:

{
    "posts": {
        "byId": {
            1: {
                id: 1,
                name: "Post One",
                user: [10]
            },
            2: {
                id: 2,
                name: "Post Two",
                user: [11]
            }
        },
        "allIds": [1, 2]
    },
    "users": {
        "byId": {
            10: {username: "User One"},
            11: {username: "User Two"}
        },
        "allIds": [10, 11]
    }
}

Это состояние, которое я считаю правильным.Теперь проблема в том, есть ли у меня действие, которое извлекает все сообщения и их пользователя, комментарии, ...

Используя normalizr, я могу нормализовать состояние, чтобы соответствовать модели выше,Когда я слушаю FETCH_POSTS_SUCCESS, в postsReducer .. Как я могу добавить пользователей в их собственный корневой путь?

Использование postsReducer приведет к

state.posts.users

вместо этого,что говорит хорошая практика, это

state.users

Ответы [ 2 ]

0 голосов
/ 13 декабря 2018

Создайте отдельные редукторы и объедините их:

function normalizeData(data, initialValue = [], idKey = 'id') {
  return data.reduce(
    (accumulator, currentValue) => ({
      ...accumulator,
      [currentValue[idKey]]: currentValue,
    }),
    {},
  );
}

function mapIds(data, initialValue = [], idKey = 'id') {
  const ids = data.map(eachData => eachData[idKey]);
  return [...initialValue, ids];
}

function posts(state = {}, action) {
  switch (action.type) {
    case types.FETCH_POSTS_SUCCESS:
      return {
        byId: normalizeData(action.payload.data, state.byId),
        allIds: mapIds(action.payload.data, state.allIds),
      };
    default:
      return state;
  }
}

function users(state = {}, action) {
  switch (action.type) {
    case types.FETCH_USERS_SUCCESS:
      return {
        byId: normalizeData(action.payload.data, state.byId),
        allIds: mapIds(action.payload.data, state.allIds),
      };
    default:
      return state;
  }
}

export default combineReducers({ posts, users });

Вы также можете создавать вспомогательные оболочки для них, которые можно использовать повторно для простого создания других редукторов сущностей:

const byIdReducerCreator = (actionType, idKey = 'id') => (state = {}, action) => {
  switch (action.type) {
    case types[actionType]:
      return normalizeData(action.payload.data, state, idKey);
    default:
      return state;
  }
};

const allIdReducerCreator = (actionType, idKey = 'id') => (state = [], action) => {
  switch (action.type) {
    case types[actionType]:
      return mapIds(action.payload.data, state, idKey);
    default:
      return state;
  }
};

const posts = combineReducers({
  byId: byIdReducerCreator('FETCH_POSTS_SUCCESS'),
  allIds: allIdReducerCreator('FETCH_POSTS_SUCCESS'),
});

const users = combineReducers({
  byId: byIdReducerCreator('FETCH_USERS_SUCCESS', 'someOtherId'),
  allIds: allIdReducerCreator('FETCH_USERS_SUCCESS', 'someOtherId'),
});

export default combineReducers({ posts, users });
0 голосов
/ 13 декабря 2018

Наивное решение: пусть ваш userReducer прослушает FETCH_POSTS_SUCCESS и обновит свое собственное состояние, если в списке постов есть какой-либо пользователь.Конечно, это загрязняет логику, поскольку FETCH_POST_SUCCESS больше не относится только к postReducer.

Существует 2 альтернативных решения, которые я могу предложить для улучшения:

Одно из них, если вы используете какой-либо пакет, напримеркак redux-thunk или redux-saga, вызывать вторичные эффекты при успешном получении сообщений.Ниже приведен пример для redux-thunk

function fetchPosts() {
    return function(dispatch) {
        return fetchPostsAPICall()
            .then((posts) => {
                dispatch(fetchPostSuccess, posts)
                const users = getUsersFromPosts()
                dispatch(massUpdateUsers, users)
            })
    }
}

Второй - использование промежуточного программного обеспечения для прослушивания FETCH_POST_SUCCESS и обработки внутри него вторичных эффектов.Пример ниже с использованием redux-saga.takeEvery

function* handleFetchPostsSuccess({ type, payload }) {
    const users = getUsersFromPayload(payload)
    yield put({ type: 'MASS_UPDATE_USERS', users })

}

function* watchFetchPosts() {
    yield takeEvery(FETCH_POSTS_SUCCESS, handleFetchPostsSuccess)
}

...

const sagaMiddleware = createSagaMiddleware()
const store = createStore(
  reducer,
  applyMiddleware(sagaMiddleware)
)
sagaMiddleware.run(watchFetchPosts)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...