简体   繁体   中英

Why state returned from my reducer is an empty object??(React-Redux)

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 this happens??

These are my components

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 './components/BookShelf'
import AllShelves from './components/AllShelves'
import Header from './components/Header';
import SearchPage from './components/SearchPage';
import * as BooksAPI from './BooksAPI';
import { Route, withRouter } from 'react-router-dom';
import './App.css';

class App extends Component {  

  componentWillMount() {
    this.props.fetchBooks();
  }

  render() {
    console.log(this.props.books)
    return (
      <div className="App">
        <Header />
        <Route exact path="/" component={AllShelves} />         
        <Route  path="/search" component={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!!!

在第二个示例中,您将在reducer中获取的值作为action.books取而代之,它应该是action.payload,因为这是在操作中分配的键。

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 coming from the action that is wrong way to do that

I've checked all your codes and I think the problem possibly come 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 componentDidMount() lifecycle hook instead of componentWillMount() , like this:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM