Reputation: 101
I'm new to redux and trying to fetch content using the Contentful API. For some reason the action I call does not reach the reducer. I have attached the code I feel is relevant and any contributions would be highly appreciated.
actions/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
};
}
reducers/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'));
components/content-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);
Upvotes: 1
Views: 1147
Reputation: 45860
You can simplify your code and avoid dispatching asynchronous actions and needing to use redux middleware by doing the following:
fetchContent()
into an async function that returns an action with the items in the payloadmapDispatchToProps
that creates a function that dispatches the action returned by fetchContent()
fetchContent()
would look like this:
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
would look like this:
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);
your reducer would look like this:
export default function(state = INITIAL_STATE, action){
switch(action.type){
case FETCH_CONTENT:
return { ...state, all: action.payload };
default:
return state;
}
}
and componentDidMount()
would look like this:
componentDidMount(){
this.props.loadItems();
}
Upvotes: 0
Reputation: 17648
Update
It seems that I'm wrong here (Thanks to @Dave Newton's comments). redux-promise
waits a promise and if it receives one, resolves it and dispatches the value. So, using an async function and using an action creator here is useless.
You are using redux-promise
, I don't know how it handles the situation but in its Github repo there is an example with redux-actions
and it uses an async function. I'm more familiar with redux-thunk
but probably it suits in your situation to use an async action creator here.
Try this:
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
};
}
Upvotes: 1