I'm trying to follow this tutorial (/@stowball/a-dummys-guide-to-redux-and-thunk-in-react-d8904a7005d3) on React Redux but am getting an empty object when I print out this.props. It seems like mapStateToProps isn't actually setting this.props since react redux's connect isn't being called, but I'm not sure why
This is what the state should be (like in the tutorial), all I did was change the component's name ItemList to Home
Here's what I'm getting (nothing was mapped to the state):
actions/items.js
export function itemsHasErrored(bool) {
return {
type: 'ITEMS_HAS_ERRORED',
hasErrored: bool
};
}
export function itemsIsLoading(bool) {
return {
type: 'ITEMS_IS_LOADING',
isLoading: bool
};
}
export function itemsFetchDataSuccess(items) {
return {
type: 'ITEMS_FETCH_DATA_SUCCESS',
items
};
}
export function itemsFetchData(url) {
return (dispatch) => {
dispatch(itemsIsLoading(true));
fetch(url)
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
dispatch(itemsIsLoading(false));
return response;
})
.then((response) => response.json())
.then((items) => dispatch(itemsFetchDataSuccess(items)))
.catch(() => dispatch(itemsHasErrored(true)));
};
}
components/Home.js
export class Home extends Component {
componentDidMount() {
console.log(this.props)
}
render() {
if (this.props.hasErrored) {
return <p>Sorry! There was an error loading the items</p>;
}
if (this.props.isLoading) {
return <p>Loading…</p>;
}
return (
<ul>
{this.props.items.map((item) => (
<li key={item.id}>
{item.label}
</li>
))}
</ul>
);
}
}
const mapStateToProps = (state) => {
return {
items: state.items,
hasErrored: state.itemsHasErrored,
isLoading: state.itemsIsLoading
};
};
const mapDispatchToProps = (dispatch) => {
return {
fetchData: (url) => dispatch(itemsFetchData(url))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Home);
reducers/index.js
export function itemsHasErrored(state = false, action) {
switch (action.type) {
case 'ITEMS_HAS_ERRORED':
return action.hasErrored;
default:
return state;
}
}
export function itemsIsLoading(state = false, action) {
switch (action.type) {
case 'ITEMS_IS_LOADING':
return action.isLoading;
default:
return state;
}
}
export function items(state = [], action) {
switch (action.type) {
case 'ITEMS_FETCH_DATA_SUCCESS':
return action.items;
default:
return state;
}
}
store/configureStore.js
import { applyMiddleware, createStore } from 'redux'
import thunk from 'redux-thunk'
import rootReducer from '../reducers'
export default function configureStore(initialState) {
return createStore(
rootReducer,
initialState,
applyMiddleware(thunk)
)
}
App.js
import React, { Component } from 'react'
import { Provider } from 'react-redux'
import configureStore from './store/configureStore'
import { Home } from './components/Home'
const store = configureStore()
export default class App extends Component {
render () {
return (
<Provider store={store}>
<Home />
</Provider>
)
}
}
index.js (I am using create-react-app boilerplate)
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
I'm trying to follow this tutorial (https://medium.com/@stowball/a-dummys-guide-to-redux-and-thunk-in-react-d8904a7005d3) on React Redux but am getting an empty object when I print out this.props. It seems like mapStateToProps isn't actually setting this.props since react redux's connect isn't being called, but I'm not sure why
This is what the state should be (like in the tutorial), all I did was change the component's name ItemList to Home
Here's what I'm getting (nothing was mapped to the state):
actions/items.js
export function itemsHasErrored(bool) {
return {
type: 'ITEMS_HAS_ERRORED',
hasErrored: bool
};
}
export function itemsIsLoading(bool) {
return {
type: 'ITEMS_IS_LOADING',
isLoading: bool
};
}
export function itemsFetchDataSuccess(items) {
return {
type: 'ITEMS_FETCH_DATA_SUCCESS',
items
};
}
export function itemsFetchData(url) {
return (dispatch) => {
dispatch(itemsIsLoading(true));
fetch(url)
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
dispatch(itemsIsLoading(false));
return response;
})
.then((response) => response.json())
.then((items) => dispatch(itemsFetchDataSuccess(items)))
.catch(() => dispatch(itemsHasErrored(true)));
};
}
components/Home.js
export class Home extends Component {
componentDidMount() {
console.log(this.props)
}
render() {
if (this.props.hasErrored) {
return <p>Sorry! There was an error loading the items</p>;
}
if (this.props.isLoading) {
return <p>Loading…</p>;
}
return (
<ul>
{this.props.items.map((item) => (
<li key={item.id}>
{item.label}
</li>
))}
</ul>
);
}
}
const mapStateToProps = (state) => {
return {
items: state.items,
hasErrored: state.itemsHasErrored,
isLoading: state.itemsIsLoading
};
};
const mapDispatchToProps = (dispatch) => {
return {
fetchData: (url) => dispatch(itemsFetchData(url))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Home);
reducers/index.js
export function itemsHasErrored(state = false, action) {
switch (action.type) {
case 'ITEMS_HAS_ERRORED':
return action.hasErrored;
default:
return state;
}
}
export function itemsIsLoading(state = false, action) {
switch (action.type) {
case 'ITEMS_IS_LOADING':
return action.isLoading;
default:
return state;
}
}
export function items(state = [], action) {
switch (action.type) {
case 'ITEMS_FETCH_DATA_SUCCESS':
return action.items;
default:
return state;
}
}
store/configureStore.js
import { applyMiddleware, createStore } from 'redux'
import thunk from 'redux-thunk'
import rootReducer from '../reducers'
export default function configureStore(initialState) {
return createStore(
rootReducer,
initialState,
applyMiddleware(thunk)
)
}
App.js
import React, { Component } from 'react'
import { Provider } from 'react-redux'
import configureStore from './store/configureStore'
import { Home } from './components/Home'
const store = configureStore()
export default class App extends Component {
render () {
return (
<Provider store={store}>
<Home />
</Provider>
)
}
}
index.js (I am using create-react-app boilerplate)
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
Share
Improve this question
edited Sep 18, 2017 at 21:09
user3226932
asked Sep 18, 2017 at 20:51
user3226932user3226932
2,24211 gold badges53 silver badges87 bronze badges
4
|
1 Answer
Reset to default 22The issue is that you're exporting two components... the non-connected (via the named export Home
with export class Home...
) and connected (via export default
). Then, you're importing and rendering the non-connected component:
import { Home } from './components/Home'
Since you want to use the connected component, you should be importing the default export like this:
import Home from './components/Home'
You may want to just export the connected component, unless you have some reason to use the unconnected one.
this.props.fetchData
at any time? I'm not seeing that in your code. – Jacob Commented Sep 18, 2017 at 21:15Provider
;Home
is the component that the store state will map props to. – Jacob Commented Sep 18, 2017 at 21:17