I have a problem in my redux reducer, it does not return expected state after dispatching FETCH_BOOKS
action, it returns an empty object instead of an object of state which is books that is fetched by AJAX request,
the reducer returns correct data when storing my state in array instead of object, this is so confusing, why does this happen??
These are my ponents
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import './index.css';
import App from './App';
import * as BooksAPI from './BooksAPI';
import registerServiceWorker from './registerServiceWorker';
import { createStore, applyMiddleware } from 'redux';
import { bookReducer } from './reducers/BookReducer';
import thunk from 'redux-thunk';
import {BrowserRouter as Router} from 'react-router-dom';
const middleware = [thunk];
const initialState = {};
const store = createStore(bookReducer, initialState, applyMiddleware(...middleware));
ReactDOM.render(
<Provider store={store}>
<Router>
<App />
</Router>
</Provider>,
document.getElementById('root')
);
registerServiceWorker();
App.js
import React, { Component } from 'react';
import { connect } from 'react-redux'
import BookShelf from './ponents/BookShelf'
import AllShelves from './ponents/AllShelves'
import Header from './ponents/Header';
import SearchPage from './ponents/SearchPage';
import * as BooksAPI from './BooksAPI';
import { Route, withRouter } from 'react-router-dom';
import './App.css';
class App extends Component {
ponentWillMount() {
this.props.fetchBooks();
}
render() {
console.log(this.props.books)
return (
<div className="App">
<Header />
<Route exact path="/" ponent={AllShelves} />
<Route path="/search" ponent={SearchPage} />
</div>
);
}
}
const mapStateToProps = (state) => {
return {
books: state.books
}
}
const mapDispatchToProps = (dispatch) => {
return {
fetchBooks: () => {
BooksAPI.getAll().then(books => dispatch({
type: 'FETCH_BOOKS',
books
}))
},
}
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App))
reducer that doesn't works
import { FETCH_BOOKS } from '../actions/Types.js';
import * as BooksAPI from '../BooksAPI'
const initialState = {
books: [],
query: ''
}
export const bookReducer = (state = initialState, action) => {
switch(action.type) {
case 'FETCH_BOOKS':
return {
...state,
books: action.books,
}
default:
return state;
}
}
The reducer that work
export const bookReducer = (state = [], action) => {
switch(action.type) {
case 'FETCH_BOOKS':
return action.books
default:
return state;
}
}
So why storing state in object doen't work and it works perfectly with array, i don't want to store my state in array, as books is not the only data i need to manage in my state!!!
I have a problem in my redux reducer, it does not return expected state after dispatching FETCH_BOOKS
action, it returns an empty object instead of an object of state which is books that is fetched by AJAX request,
the reducer returns correct data when storing my state in array instead of object, this is so confusing, why does this happen??
These are my ponents
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import './index.css';
import App from './App';
import * as BooksAPI from './BooksAPI';
import registerServiceWorker from './registerServiceWorker';
import { createStore, applyMiddleware } from 'redux';
import { bookReducer } from './reducers/BookReducer';
import thunk from 'redux-thunk';
import {BrowserRouter as Router} from 'react-router-dom';
const middleware = [thunk];
const initialState = {};
const store = createStore(bookReducer, initialState, applyMiddleware(...middleware));
ReactDOM.render(
<Provider store={store}>
<Router>
<App />
</Router>
</Provider>,
document.getElementById('root')
);
registerServiceWorker();
App.js
import React, { Component } from 'react';
import { connect } from 'react-redux'
import BookShelf from './ponents/BookShelf'
import AllShelves from './ponents/AllShelves'
import Header from './ponents/Header';
import SearchPage from './ponents/SearchPage';
import * as BooksAPI from './BooksAPI';
import { Route, withRouter } from 'react-router-dom';
import './App.css';
class App extends Component {
ponentWillMount() {
this.props.fetchBooks();
}
render() {
console.log(this.props.books)
return (
<div className="App">
<Header />
<Route exact path="/" ponent={AllShelves} />
<Route path="/search" ponent={SearchPage} />
</div>
);
}
}
const mapStateToProps = (state) => {
return {
books: state.books
}
}
const mapDispatchToProps = (dispatch) => {
return {
fetchBooks: () => {
BooksAPI.getAll().then(books => dispatch({
type: 'FETCH_BOOKS',
books
}))
},
}
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App))
reducer that doesn't works
import { FETCH_BOOKS } from '../actions/Types.js';
import * as BooksAPI from '../BooksAPI'
const initialState = {
books: [],
query: ''
}
export const bookReducer = (state = initialState, action) => {
switch(action.type) {
case 'FETCH_BOOKS':
return {
...state,
books: action.books,
}
default:
return state;
}
}
The reducer that work
export const bookReducer = (state = [], action) => {
switch(action.type) {
case 'FETCH_BOOKS':
return action.books
default:
return state;
}
}
So why storing state in object doen't work and it works perfectly with array, i don't want to store my state in array, as books is not the only data i need to manage in my state!!!
Share Improve this question edited Nov 27, 2021 at 15:27 Rifky Niyas 2,0761 gold badge14 silver badges29 bronze badges asked Oct 7, 2018 at 2:41 Saher ElgendySaher Elgendy 1,6194 gold badges17 silver badges32 bronze badges 4- I'm confused now! Which one is the one that works and which not? – Tu Nguyen Commented Oct 7, 2018 at 2:47
- sorry i edited it – Saher Elgendy Commented Oct 7, 2018 at 2:49
-
Not sure about what are you intending to ask. You say state as an object doesn't work, but the working reducer example returns state as an object. And for the not working reducer you are returning an array for the state. If you look at you action, you are returning data as payload but in the reducer you are trying to return
action.books
which obviously is undefined. You need to returnaction.payload
like in the working reducer example. – Vinit Sarvade Commented Oct 7, 2018 at 2:51 - @Vinit Sarvade i already edited that – Saher Elgendy Commented Oct 7, 2018 at 2:55
3 Answers
Reset to default 3I've checked all your codes and I think the problem possibly e from the redux store setup:
const initialState = {};
const store = createStore(bookReducer, initialState, applyMiddleware(...middleware));
I suggest removing the initialState:
const initialState = {}; // remove this line cuz we don't need it
const store = createStore(bookReducer, applyMiddleware(...middleware)); //fixed like this
In addition, I think you should fetch your books in the ponentDidMount()
lifecycle hook instead of ponentWillMount()
, like this:
ponentDidMount() {
this.props.fetchBooks();
}
In the second example, you are fetching the value in the reducer as action.books
, instead it should be action.payload
because that's the key dispatched in action.
After any Action is dispatched you have to return a new state to the store so you have to return new state object for that you have to get the state now and change the books and return the new state so following code doing that
export const bookReducer = (state = initialState, action) => {
switch(action.type) {
case 'FETCH_BOOKS':
return {
...state,
books: action.books,
}
default:
return state;
}
}
but from the other reducer you return only the books array that ing from the action that is wrong way to do that