Задать вопрос

Как сделать правильно ajax запрос в React Redux?

В общем пытаюсь разобраться во Flux подходе в React в RoR. Посоветовали для изучения Redux.
Поставил gem 'react-rails'.

Redux ставил через npm
package.json - выглядит примерно так.
{
  "version": "0.1.1",
  "main": "index.js",
  "dependencies": {
    "react": "^0.13.3",
    "react-redux": "^1.0.1",
    "redux": "^1.0.1",
    "redux-thunk": "^0.1.0"
  },
  "devDependencies": {
    "babelify": "^6.2.0",
    "browserify": "^11.0.1",
    "browserify-incremental": "^3.0.1"
  }
}


Так вот, пытаюсь получить ajax с сервера. Я понял что его надо делать в action. Но как?

Сейчас action выглядит так.
export const LOAD_INFO = 'LOAD_INFO';

export function loadInfo() {
  return {
    type: 'LOAD_INFO',
    info: // ?
  }
}


До этого в компоненте я делал это примерно так.
componentDidMount: function() {
  $.ajax({
    url: this.props.url,
    dataType: 'json',
    type: 'GET',
    success: function(data, textStatus, jqXHR) {
      this.setState({
        book: data.book,
        magazine: data.magazine
      });
    }.bind(this),
    error: function(xhr, status, err) {
      console.error(this.props.url, status, err.toString());
    }.bind(this)
  });
}


UPD:
В action получаю данные с сервера.
import request from 'axios';

export const LOAD_INFO = 'LOAD_INFO';

export function loadInfo() {
  return {
    type: 'LOAD_INFO',
    info: request.get(Routes.root_path(), {
      headers: {
        'Accept': 'application/json'
      }
    })
  }
}


reducer
import { LOAD_INFO }
from '../actions/action';

export default function info(state = 0, action) {
  switch (action.type) {

    case LOAD_INFO:
      return action;

    default:
      return state;
  }
}


component
import React, { Component, PropTypes } from 'react';

class Info extends Component {
  render() {
    const { info } = this.props;
    return (
      <div>
        { info }
      </div>
    );
  }
}

Info.propTypes = {
  info: PropTypes.object.isRequired
};

export default Info;
  • Вопрос задан
  • 15121 просмотр
Подписаться 10 Оценить Комментировать
Решения вопроса 2
@vsuhachev
Т.к. ajax запросы асинхронные то на каждый такой запрос делается 3 ветки развития событий:
  • запрос отправлен
  • запрос завершился успешно
  • запрос завершился с ошибкой


В коде это будет выглядеть как-то так
export function loadInfo() {
    return dispatch => {

        dispatch({
            type: 'LOAD_INFO_REQUESTED'
        });

        request.get(
            Routes.root_path(),
            {headers: {'Accept': 'application/json'}}
        )
            .then(result => {
                dispatch({
                    type: 'LOAD_INFO_OK',
                    info: result.data
                })
            })
            .catch(result => {
                dispatch({
                    type: 'LOAD_INFO_FAIL',
                    errors: result.statusText
                })
            })
    }
}

Т.е. сначала экшн оповещает хранилище(store) что начал запрос и делает сам запрос. Далее в зависимости от результата хранилище будет оповещено либо от успехе либо об неудаче.
Чтобы получить доступ к dispatch внутри экшена используется redux-thunk, который вы уже установили.

Далее редуцер, обрабатывается 3 типа событий из экшена
const defaultState = { loading: false, info: null, errors: null };

export default function info(state = defaultState, action) {
  switch (action.type) {

    case LOAD_INFO_REQUESTED:
      return { loading: true };

    case LOAD_INFO_OK:
      return { loading: false, info: action.info, errors: null };

    case LOAD_INFO_FAIL:
      return { loading: false, info: null, errors: action.errors };

    default:
      return state;
  }
}


Компонент должен быть подключен к хранилищу с помощью connect, без него компонент не увидит store
@connect(state => ({
    info: state.info
}))

class Info extends Component {

    componentDidMount() {
        const { dispatch } = this.props;
        dispatch(loadInfo()) // Вызываем загрузку
    }

  render() {
    const { loading, info, errors } = this.props.info;

    if (loadind) { return (<div>Loading</div>) }
    if (errors != null) { return (<div>Error!</div>) }
    return (
      <div>
        { info }
      </div>
    );
  }
}


Вобщем как-то так. В хэлпе на redux это все описано.
Ответ написан
rajdee
@rajdee
Front-end developer
Посмотрите, как это сделано в примере async

В action у вас только описывается объект, по типу которого вызовется соответствующий редьюсер, который и отдаст уже новый state.

Соответственно, в componentDidMount должен вызываться метод dispatch(loadInfo(...))
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
maxfarseer
@maxfarseer
https://maxpfrontend.ru, обучаю реакту и компании
Сделал подобный туториал, где разбираются и асинхронные запросы тоже. Буду рад если помогу - https://www.gitbook.com/book/maxfarseer/redux-cour...
Ответ написан
mattedev
@mattedev
web developer
Есть отличный модуль, axios. Возвращает промисы. Очень удобно
Ответ написан
Комментировать
@Dolinskaya
Поправочка, в const defaultState = { loading: true, info: null, errors: null };
Т.к. когда мы начинаем диспатчить наш запрос к API, у нас по умолчанию идет загрузка, а loading: false только лишь в случае ответа, либо ошибки. Если указывать первоначально loading: false, то тяжко отловить момент, когда у нас info !== null
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы