Доступ к параметрам запроса в асинхронном вызове (react redux)

В моем проекте react redux (4.4.5) используется react-router-redux (4.0.5) и redux-async-connect (0.1.13). Прежде чем загружать компонент-контейнер, я хочу асинхронно загрузить данные из своего API. URL-адрес содержит параметр запроса с именем «категория», который используется для получения сообщений. т.е. пользователь/корнел/сообщения?категория=реагировать-редукс

Параметры, связанные с моим местоположением/путем, находятся в state.routing.locationBeforeTransitions, но они не обновляются при асинхронном вызове. Я могу получить параметры пути из параметра params, который передается асинхронной функции, но он не содержит параметров запроса.

@statics({
  reduxAsyncConnect(params, store) {
    const { dispatch } = store;
    return Promise.all([
      dispatch(loadMessages(category)) <-- need the query parameter "category" here
    ]);
  }
})
@connect(state => ({
  messages: state.user.messages
}))
export default class HomeContainer extends Component {
  static propTypes = {
    dispatch: PropTypes.func
    messages: PropTypes.array.isRequired
  };

  render() {
    const { messages } = this.props;

    return (
      ...
    }
  }
}

Кто-нибудь знает, как мне получить доступ к параметру запроса, чтобы он работал как на стороне клиента, так и на стороне сервера? Заранее спасибо!


person Cornel Janssen    schedule 19.09.2016    source источник


Ответы (1)


Вы должны иметь возможность получить поиск из состояния избыточности, как показано ниже, если вы используете react-redux-router.

@statics({
  reduxAsyncConnect(params, store) {
    const { dispatch } = store;
    return Promise.all([
      dispatch(loadMessages(category)) <-- need the query parameter "category" here
    /* you might get 
      store.getState().
          routing.locationBeforeTransitions.search 
      from here too */
    ]);
  }
})
@connect(state => ({
  messages: state.user.messages,
  /* get search from redux state */
  search : state.routing.locationBeforeTransitions.search
}))
export default class HomeContainer extends Component {
  static propTypes = {
    dispatch: PropTypes.func
    messages: PropTypes.array.isRequired
  };

  render() {
    const { messages } = this.props;

    return (
      ...
    }
  }
}

Дайте мне знать, если он недоступен для вас.

РЕДАКТИРОВАТЬ

Вот фрагмент кода, который не использует reduxAsyncConnect и выполняет то, что вы хотите сделать.

// CONSTANTS
const
  GET_SOMETHING_FROM_SERVER = 'GET_SOMETHING_FROM_SERVER',
  GET_SOMETHING_FROM_SERVER_SUCCESS = 'GET_SOMETHING_FROM_SERVER_SUCCESS',
  GET_SOMETHING_FROM_SERVER_FAIL = 'GET_SOMETHING_FROM_SERVER_FAIL';

// REDUCER
const initialState = {
  something : [],
  loadingGetSomething: false,
  loadedGetSomething:false,
  loadGetSomethingError:false
};

export default function reducer(state = initialState, action) {

  switch(action.type) {

    case GET_SOMETHING_FROM_SERVER:
      return Object.assign({}, state, {
        loadingGetSomething: true,
        loadedGetSomething:false,
        loadGetSomethingError:false
        something : [] // optional if you want to get rid of old data
      });
    case GET_SOMETHING_FROM_SERVER_SUCCESS:
      return Object.assign({}, state, {
        loadingGetSomething: false,
        loadedGetSomething:true,
        something : action.data
      });
    case GET_SOMETHING_FROM_SERVER_FAIL:
      return Object.assign({}, state, {
        loadingGetSomething: false,
        loadGetSomethingError: action.data
      });
    default:
      return state;
  }

};

// ACTIONS

/* ----------------- GET SOMETHING ACTIONS START ----------------- */
import Fetcher from 'isomorphic-fetch'; // superagent , axios libs are okay also 

export function getSomething() {
  return {
    type : GET_SOMETHING_FROM_SERVER
  }
};
export function getSomethingSuccess(data) {
  return {
    type : GET_SOMETHING_FROM_SERVER_SUCCESS,
    data
  }
};
export function getSomethingFail(data) {
  return {
    type : GET_SOMETHING_FROM_SERVER_FAIL,
    data
  }
};
export function getSomethingAsync(paramsToBeSentFromComponents){
  return function(dispatch) {
    const fetcher = new Fetcher();

    dispatch(getSomething()); // so we can show a loading gif 

    fetcher
      .fetch('/api/views', {
        method : 'POST',
        data : {
          // use paramsToBeSentFromClient
        }
      })
      .then((response) => {
        dispatch( getSomethingSuccess(response.data));
      })
      .catch((error) => {
        return dispatch(getSomethingFail({
          error : error        
        }))
      });
  }
}
/* ----------------- GET SOMETHING ACTIONS END ----------------- */


// COMPONENT

import React, {Component}       from 'react';
import { connect }              from 'react-redux';
import { bindActionCreators }   from 'redux';
import * as somethignActions    from './redux/something';

@connect((state) => ({
  pathname : state.routing.locationBeforeTransitions.pathname,
  something : state.something
}))

export default class SettingsMain extends Component{

  constructor(props){
    super(props);
    this.somethingActions = bindActionCreators(somethingActions, this.props.dispatch);
  }

  componentDidMount(){
    // you are free to call your async function whenever 
    this.settingActions.getSomething({ this.props.pathname...... })
  }

  render(){
    return ( /* your components */ )
  }
}
person FurkanO    schedule 19.09.2016
comment
store.getState(). routing.locationBeforeTransitions.search — пустая строка. Я думаю, это потому, что он не обновлен до последнего изменения URL. Он доступен, хотя и на реальных реквизитах при рендеринге компонента. - person Cornel Janssen; 19.09.2016
comment
Когда вам нужно запустить эту функцию? После того, как ваш компонент смонтирован на странице по другому маршруту или до этого? Я также не знаком с reduxAsyncConnect. Вы можете легко вызвать свою асинхронную функцию из компонента и передать полученные реквизиты... поиск по componentWillMount или что-то в этом роде. - person FurkanO; 19.09.2016
comment
reduxAsyncConnect запускает функцию до того, как компонент будет смонтирован. Раньше он работал с react-router-redux v3. - person Cornel Janssen; 19.09.2016
comment
Я понимаю. Я взглянул на reduxAsyncConnect, и, кажется, он делает свой первый запрос в componentDidMount(). Это должно означать, что вы должны иметь возможность получить newProps. Вы можете попытаться поместить отладчик в свой код, чтобы увидеть, не является ли оно устаревшим состоянием редукции, которое получает ваш reduxAsyncConnect. - person FurkanO; 19.09.2016
comment
store.getState(). routing.locationBeforeTransitions устарел в reduxAsyncConnect. Все еще имеет старые значения (путь, запрос), в то время как свойства в рендере имеют правильные значения. - person Cornel Janssen; 19.09.2016
comment
Я бы искренне не рекомендовал вам использовать reduxAsyncConnect, если это возможно. React-redux-universal сделал его известным, но проще написать свои асинхронные функции самостоятельно. - person FurkanO; 19.09.2016
comment
Возможно, у вас есть хорошие и проверенные примеры? Проект, над которым я работаю, довольно большой, поэтому его рефакторинг потребует немало работы. Кстати, спасибо за быстрые ответы! - person Cornel Janssen; 19.09.2016