Напишите действие и редуктор эффективно и чисто (реагируйте на редукцию)

У меня есть следующие действия и редуктор:

действия:

import { OPEN_NODE, CLOSE_NODE, GET_NODES } from '../constants/NodeActionTypes';

export function openNode(path) {
  return {
    type: OPEN_NODE,
    path: path
  };
}

export function closeNode() {
  return {
    type: CLOSE_NODE
  };
}


export function getNodes(path) {
  return {
    type: GET_NODES,
    path: path
  };
}

редуктор:

export default function opener(state = initialState, action) {
  switch (action.type) {
  case OPEN_NODE:
    var { path } = action
    var {nodes} = getFileList(path)
    return {
      ...state,
      open:true,
      nodes:nodes
    };
  case CLOSE_NODE:
    return {
      ...state,
      open:false
    };
  case GET_NODES:
    var { path } = action
    var {nodes} = getFileList(path)
    return {
      ...state,
      nodes:nodes
    };
  default:
    return state;
  }
}

Очевидно, что OPEN_NODE содержит GET_NODES (только плюс open:true), но кажется, что есть много способов организовать код:

  1. упакуйте редюсер GET_NODES в функцию, вызовите его в OPEN_NODE и добавьте open:true.

  2. изменить действие openNode, отправить [OPEN_NODE, GET_NODES] вместе, но как написать случай switch(action.type)?

  3. пусть OPEN_NODE редуктор отправит действие getNodes для запуска GET_NODES редуктора

что лучше? Или любой другой лучший способ?


person Mithril    schedule 21.06.2016    source источник
comment
вы, по сути, спрашиваете, как составить свой редуктор. Позвольте мне указать вам правильное направление: egghead.io/courses/getting-started-with -редукс. понимание этого курса может помочь со всеми четырьмя вашими вопросами о сокращении.   -  person xiaofan2406    schedule 22.06.2016


Ответы (3)


Вам не нужно держать все внутри оператора switch. Если у вас есть 2 похожих действия, просто преобразуйте их в приватную функцию и вызовите ее.

В вашем случае это может быть что-то вроде:

// your reducer helper
const getNodes = (state) => {
 var { path } = action
 var {nodes} = getFileList(path)
 return {
   ...state,
   nodes:nodes
 };
};

// your reducer function
export default function opener(state = initialState, action) {
  switch (action.type) {
  case OPEN_NODE:
    return { ...getNodes(state), open:true };
  case GET_NODES:
    return getNodes(state);
  // ....
}
person mnsr    schedule 21.06.2016
comment
Да, я думаю, что вариант 1 тоже хорош, но есть ли какие-нибудь мысли о вариантах 2 и 3? Какие преимущества и недостатки? - person Mithril; 24.06.2016

Вы можете просто использовать оператор switch для выполнения обоих действий:

export default function opener(state = initialState, action) {
  switch (action.type) {
  case OPEN_NODE:
  case GET_NODES:
    var { path } = action
    var {nodes} = getFileList(path)
    return {
      ...state,
      nodes:nodes
      open: action.type === OPEN_NODE ? true : state.open
    };
  case CLOSE_NODE:
    return {
      ...state,
      open:false
    };
  default:
    return state;
  }
}
person Pierre Criulanscy    schedule 21.06.2016
comment
Я не думаю, что это хороший способ. Если OPEN_NODE потребуется больше состояний в будущем, или есть что-то, вызывающее OPEN_NODE_2, нужно новое состояние open2, код будет уродливым, полным action.type === xxx ? true : xxx - person Mithril; 21.06.2016
comment
Если вы видите этот паттерн много раз, это сигнал к тому, что вам нужно провести рефакторинг. Но для вашего конкретного случая использования это не так уж и плохо на самом деле. - person Pierre Criulanscy; 21.06.2016

Посмотрите мой проект на github для создания универсальных редукторов. Решение, которое я намереваюсь решить, решит многие проблемы, которые у вас есть в настоящее время.

Redux-Reducer-Generator

person Thuthinh    schedule 12.07.2018