Невозможно преобразовать глубокое клонирование в immer - PullRequest
0 голосов
/ 19 сентября 2018

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

export default (initialState, handlers = {}, promiseActionTypes = []) =>
  (state = initialState, action) => {
    let nextState = _.cloneDeep(state)
    promiseActionTypes.forEach((actionType) => {
      if (action.type === `@@REMOTE/${actionType}_REQUEST`) {
        nextState.isFetching = true
      }
      if (action.type === `@@REMOTE/${actionType}_SUCCESS`) {
        nextState = {
          ...nextState,
          data: _.get(action, 'data.storeData', action.data),
          isFetching: false,
          isInited: true,
        }
      }
      if (action.type === `@@REMOTE/${actionType}_FAILURE`) {
        nextState.isFetching = false
      }
    })
    if (handlers.hasOwnProperty(action.type)) {
      nextState = handlers[action.type](nextState, action, _.cloneDeep(state))
    }
    return nextState
  }

Все эти глубокие клоны - это большие запреты, поэтому я пытаюсь использовать функцию производства в immer для преобразованияподготовленные копии состояния перед возвратом в новое состояние.

Проблема в том, что я не смог получить все в синхронизации.Некоторые кусочки состояния не будут корректно обновляться здесь или там.Вот моя попытка рефакторинга до сих пор:

import produce from 'immer'

export default (initialState, handlers = {}, promiseActionTypes = []) =>
  (state = initialState, action) => {
    return produce(state, (draft) => {
      promiseActionTypes.forEach((actionType) => {
        if (action.type === `@@REMOTE/${actionType}_REQUEST`) {
          draft.isFetching = true
        }
        if (action.type === `@@REMOTE/${actionType}_SUCCESS`) {
          draft.data = _.get(action, 'data.storeData', action.data)
          draft.isFetching = false
          draft.isInited = true
        }
        if (action.type === `@@REMOTE/${actionType}_FAILURE`) {
          draft.isFetching = false
        }

        return draft
      })

      if (handlers.hasOwnProperty(action.type)) {
        return handlers[action.type](draft, action, state)
      }

      return draft
    })
  }

Я пытался разморозить затронутые объекты, но все еще не играл в кости.Моя реализация только что выключена?Или я неправильно понимаю, как работают продукты?

Черт, мне когда-нибудь нужно что-то вроде immer, если я просто пытаюсь получить оттуда эти два lodash cloneDeep вызова?

РЕДАКТИРОВАТЬ:Вот пример пользовательского обработчика, который будет вызывать последнюю строку:

  LOCATION_CHANGE: (state, action) => {

    // bootstrap
    if (_.isUndefined(state.location)) {
      state.location = action.location
    }

    state.next = {
      location: action.location,
      changed: action.changed,
    }
    state.isNavigating = true
    return state
  },
  VIEW_ROUTE_MATCH: (state, action) => {
    state.next = {
      ...state.next,
      match: action.match,
      view: action.view,
    }
    return state
  },

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

Я бы сказал, что вам не нужно Иммер, в данном случае, поскольку вы на самом деле не делаете глубоких или сложных изменений, но это все равно может помочь привести в порядок детали.Иммер собирается форсировать три строки кода, поэтому я буду придерживаться оператора распространения, если он останется в одной строке.

export default (initialState, handlers = {}, promiseActionTypes = []) =>
  (state = initialState, action) => {
    let nextState = state;
    promiseActionTypes.forEach((actionType) => {
      if (action.type === `@@REMOTE/${actionType}_REQUEST`) {
        nextState = { ...nextState, isFetching: true };
      }
      if (action.type === `@@REMOTE/${actionType}_SUCCESS`) {
        nextState = produce(state, draft => {
          draft.data = _.get(action, 'data.storeData', action.data);
          draft.isFetching = false;
          draft.isInited = true;
        });
      }
      if (action.type === `@@REMOTE/${actionType}_FAILURE`) {
        nextState = { ...nextState, isFetching: false };
      }
    })

    if (handlers.hasOwnProperty(action.type)) {
      nextState = handlers[action.type](nextState, action);
    }

    return nextState
  }

const handlers = {
  LOCATION_CHANGE: (state, action) => {
    return produce(state, draft => {
      if (_.isUndefined(state.location)) {
        draft.location = action.location;
      }
      draft.next = {
        location: action.location,
        changed: action.changed,
      }
      draft.isNavigating = true
    });
  },
  VIEW_ROUTE_MATCH: (state, action) => {
    return produce(state, draft => {
      draft.match = action.match;
      draft.view = action.view;
    });
  },
}
0 голосов
/ 19 сентября 2018

Первая проблема заключается в том, что ваш исходный код вообще не должен был делать "глубокое клонирование", и особенно не в верхней части редуктора.Это означает, что он выполнял дополнительную работу для каждого отправленного действия, даже если оно не было релевантным, а также, вероятно, вызывало повторный рендеринг пользовательского интерфейса, даже если значения данных действительно не изменились.Итак, как вы сказали, «большое нет-нет».Исходя из этого, да, я бы сказал, что Immer здесь полезен.

Во-вторых, вам не следует использовать promiseActionTypes.map() концептуально, поскольку вы пытаетесь выполнить некоторые обновления вместо того, чтобы возвращать новый массив.Используйте .forEach(), как это делал оригинальный код.

В-третьих, вы не описали , какие поля не обновляются должным образом, так что это немного сложно

Beyondчто код draft выглядит хорошо.Однако в этом случае строка handlers выглядит подозрительно.Я предполагаю, что эти дополнительные обработчики, вероятно, выполняют свою собственную неизменную работу, а не пытаются "изменить" значение состояния draft.О, и вы все равно даже не передаете им draft.Итак, если вы ожидаете, что они будут генерировать остальные изменения, вам нужно A) передать draft в обработчики и B) изменить их, чтобы «изменить» черновик.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...