Ответы пользователя по тегу Redux
  • React + Redux. Правильное использование QueryString и componentWillReceiveProps?

    В такой ситуации компонент следует подключить к redux'у через connect. Тогда у вас будет возможность смотреть, что уже загружено, а что нет.

    Если у вас какая-то сложная логика - я бы предложил сделать флаг isLoaded и передавать его как props в компонент. Затем, в методе componentWillReceiveProps вы можете проверить, если этот флаг сброшен - вызвать функцию загрузки.

    Но конкретно в этом случае лучше поступить так, как сделано в официальном примере real-world-example: проверять изменился-ли номер страницы и только в этом случае диспатчить действия.

    UPD1. Пример кода:
    // MyComponent
    import shallowequal from 'shallowequal';
    
    export default class MyComponent {
      static propTypes = {
        items: PropTypes.array.isRequired,
        filtres: PropTypes.object.isRequired, // <-- тут можно собрать все фильтры
      };
    
      componentWillReceiveProps(nextProps) {
        if(!shallowequal(this.props.filtres, nextProps.filtres)) {
            loadData(filtres);
        };
      }
    }


    // MyComponentContainer
    import MyComponent from './MyComponent';
    
    function mapState(state, ownProps) {
      return {
        items: applyFiltres(state.someReducer.someItems),
        filtres: ownProps.location.query, // <--- как пример
      };
    }
    
    export default connect(mapState)(MyComponent);


    В этом случае наш компонент (MyComponent) независим от роутера и от редакса. При этом метод componentWillReceiveProps достаточно простой.
    Ответ написан
    6 комментариев
  • Где и как нужно сделать AJAX запрос в redux?

    Для работы с promise Вам нужно использовать дополнительный middleware - promise middleware. Существует несколько реализаций - можете выбрать любой понравившийся. Я использую этот и относительно него буду далее писать.

    Как я понял, запрос пишется в action creator при помощи промиса


    Да, все так. В экшен-креаторе делаем запрос, возвращаем экшен с промисом. Далее promiseMiddleware подхватывает его и вместо одного экшена диспатчит 3 - действие началось, действие завершилось успешно, действие завершилось с ошибкой. Все это происходит в зависимости от того в какое состояние попал вышеупомянутый promise. Другими словами - "действие началось" диспатчится сразу; если запрос успешен - диспатчится "действие завершилось успешно".
    Соответственно в вашем редьюсере Вы подписываетесь на это три действия. Пример:

    // action creator
    import fetch from 'isomorphic-fetch';
    
    export default function getBook() {
      // Для запросов чаще всего используется  isomorphic-fetch, который возвращает promise
      const promise = fetch(url, options);
      return {
        types:  [ 'GET_BOOK-BEGIN', 'GET_BOOK-SUCCESS', 'GET_BOOK-FAILURE' ],
        promise,
      };
    }


    // reducer
    import {GET_BOOK} from '../actions/books';
    
    const booksReducer = (state = {}, action) => {
      switch (action.type) {
        case 'GET_BOOK-SUCCESS':
          // При успешном завершении у нас установлено свойство result с ответом сервера
          return action.result;
        case 'GET_BOOK-FAILURE':
          // При неудачном завершении у нас установлено свойство error с описанием ошибки
          doSomethingWithError(action.error); // <--- просто для примера
        default:
          return state;
      }
    };
    
    export default booksReducer;


    UPD1 К слову: у редакса есть отличный пример, где все это можно в живую посмотреть - https://github.com/rackt/redux/tree/master/example...
    Ответ написан
    6 комментариев
  • Как мне написать redux reducer?

    Если делать все правильно, то во-первых вам нужно нормализовать все это дело. Чтобы получился список папок (я рекомендую хранить в хэшмапе id => entity):
    folders: {
      '123': {
        id: 123,
        name: 'Inbox',
        isSelected: false,
        parentId: 123,
        visible: false,
      },
    }


    Собственно после этого создание reducer'a превратиться в довольно простую задачу:
    function folder(action, state = initialState) {
      switch(action.type) {
        case OPEN_FOLDER_ACTION:
          const nextFolders = _.mapValues(state.folders, folder => {
             // Устанавливаем флаг "выбрана" для выбранной папки
            if (folder.id === action.targetId) {
              return { ...folder, isSelected: true };
            }
             // Для дочерних папок устанавливаем флаг видимости
            if (folder.parentId === action.targetId) {
              return { ...folder, visible: true };
            }
            return folder;
          });
          return {
            ...state,
            folders: { ...nextFolders },
          };
      // ...
      }
    }
    Ответ написан
    Комментировать