Действие не запускает редуктор в redux

Я новичок в redux и пытаюсь получить контент с помощью Contentful API. По какой-то причине вызываемое мной действие не доходит до редуктора. Я приложил код, который, по моему мнению, имеет отношение к делу, и мы будем очень благодарны за любой вклад.

действия / index.js

import axios from 'axios';

const API_BASE_URL = 'https://cdn.contentful.com';
const API_SPACE_ID = 'xxxxxxxxxxxxx';
const API_KEY ='xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

const FETCH_CONTENT = 'fetch_content';

export function fetchContent() {
  const request = axios.get(`${API_BASE_URL}/spaces/${API_SPACE_ID}/environments/master/entries?access_token=${API_KEY}`);
  return {
    type: FETCH_CONTENT,
    payload: request
  };
  }

редукторы / index.js

import { combineReducers } from 'redux';
import ContentReducer from './reducer-content';

const rootReducer = combineReducers({
  contents: ContentReducer
});

export default rootReducer;

reducer-content.js

import {FETCH_CONTENT} from '../actions';
const INITIAL_STATE = { all: [] };

export default function(state = INITIAL_STATE, action){
  switch(action.type){
    case FETCH_CONTENT:
      return { ...state, all: action.payload.data.items };

  default:
  return state;
  }
}

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { BrowserRouter, Route, Switch } from "react-router-dom";
import promise from 'redux-promise';
import { logger } from 'redux-logger'


import ContentIndex from './components/content-index';
import reducers from './reducers';

const createStoreWithMiddleware = applyMiddleware(promise, logger)(createStore);

ReactDOM.render(
  <Provider store={createStoreWithMiddleware(reducers)}>
    <BrowserRouter>
      <div>
      <Route  path = "/" component = {ContentIndex}/>
    </div>
    </BrowserRouter>

  </Provider>
  , document.querySelector('.container'));

компоненты / контент-index.js

import React, {Component} from 'react';
import {fetchContent} from '../actions';
import {connect} from 'react-redux';
import _ from 'lodash';

class ContentIndex extends Component {
  componentDidMount(){
    this.props.fetchContent();
  }

  renderContent(props){
    return this.props.contents.map((content, index) => {
      return (
        <article key={content.sys.id}>
          <h3>{content.fields.name}</h3>
          <p>{content.fields.website}</p>
        </article>
      );
    });
  }

  render(){
    return(
      <div>
      <h3>Content</h3>
      {this.renderContent()}
      </div>
    );
  }
}

const mapStateToProps = (state) => {
  return {contents: state.contents.all};
}
// export default CharacterIndex;
export default connect(mapStateToProps, {fetchContent})(ContentIndex);

Как сказал devserkan, вам нужно асинхронное действие, потому что axios всегда возвращает обещания, а не данные ответа напрямую. Асинхронная функция - самый простой способ справиться с этим, но вам нужно иметь правильное промежуточное программное обеспечение в redux.

Garrett Motzner 10.08.2018 17:38

Похоже, redux-promise ждет обещания, я не догадался. Итак, когда вы помещаете console.log в создатель действий и редуктор, где он терпит неудачу? Я имею ввиду где перестали логироваться?

devserkan 10.08.2018 17:52
1
2
930
3

Ответы 3

Обновлять

Похоже, я здесь ошибаюсь (спасибо комментариям @Dave Newton). redux-promise ожидает обещания и, если он его получает, разрешает его и отправляет значение. Таким образом, использование асинхронной функции и создание действия здесь бесполезно.


Вы используете redux-promise, я не знаю, как он справляется с ситуацией, но в его репозитории Github есть пример с redux-actions, и он использует функцию async. Я больше знаком с redux-thunk, но, вероятно, в вашей ситуации лучше использовать здесь средство создания асинхронных действий.

Попробуй это:

export async function fetchContent() {
  const request = await axios.get(`${API_BASE_URL}/spaces/${API_SPACE_ID}/environments/master/entries?access_token=${API_KEY}`);
  return {
    type: FETCH_CONTENT,
    payload: request
  };
}

В redux-prom ожидает, что полезная нагрузка будет обещанием; когда обещание разрешается, редуктор вызывается с разрешенным обещанием (но не в случае его отклонения). Здесь вы просто создаете обычное действие, и это нормально, но делает сокращение-обещание бессмысленным.

Dave Newton 10.08.2018 17:38

@DaveNewton, так я ошибаюсь? Сначала я подозревал, что, но, увидев пример redux-actions, я решил, что ему нужны разрешенные данные. github.com/redux-utilities/redux-promise

devserkan 10.08.2018 17:41

«Если он получает обещание, он отправляет разрешенное значение обещания. Он не отправляет ничего, если обещание отклоняется». Если вы выполняете async / await, вы просто создаете обычное (асинхронное) действие. Это нормально, но делает redux-обещание больше не таким полезным. (Хотя я все равно перестал использовать redux-prom по другим причинам, какое-то время это была полезная абстракция.)

Dave Newton 10.08.2018 17:42

Понятно. Я пропустил эту часть и просмотрел пример. Это меня смутило. Я собираюсь обновить свой ответ. Спасибо!

devserkan 10.08.2018 17:44

@devserkan Я думаю, что теперь все имеет для меня смысл. Однако в моей консоли не появляется сообщение об ошибке: Uncaught ReferenceError: refreshratorRuntime не определен.

Jared Mudd 10.08.2018 18:08

@devserkan Похоже, это в моем действии fetchContent. Если я отключу асинхронный режим, он исчезнет.

Jared Mudd 10.08.2018 18:30

Так, может быть, проблема с загрузкой из API?

devserkan 10.08.2018 18:31

axios.get () возвращает обещание.

Итак, вам нужно использовать async / await.

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

  • Преобразование fetchContent() в асинхронную функцию, которая возвращает действие с элементами в полезной нагрузке.
  • создать mapDispatchToProps, который создает функцию, которая отправляет действие, возвращаемое fetchContent()

fetchContent() будет выглядеть так:

export async function fetchContent() {
  const request = await axios.get(`${API_BASE_URL}/spaces/${API_SPACE_ID}/environments/master/entries?access_token=${API_KEY}`);
  return {
    type: FETCH_CONTENT,
    payload: request.data.items
  };
}

connect будет выглядеть так:

const mapStateToProps = (state) => {
  return {contents: state.contents.all};
}

const mapDispatchToProps = (dispatch) => {
  return {
    loadItems: () => fetchContent().then(action => dispatch(action))
  }
}

// export default CharacterIndex;
export default connect(mapStateToProps, mapDispatchToProps)(ContentIndex);

ваш редуктор будет выглядеть так:

export default function(state = INITIAL_STATE, action){
  switch(action.type){
    case FETCH_CONTENT:
      return { ...state, all: action.payload };

  default:
  return state;
  }
}

и componentDidMount() будет выглядеть так:

  componentDidMount(){
    this.props.loadItems();
  }

@JaredMudd дружеское напоминание о необходимости принять ответ, если он предоставляет необходимую информацию

Brian Adams 13.08.2018 17:00

Другие вопросы по теме