Async initial state React-Redux Redux-Thunk

2019-06-15 15:54发布

问题:

Using React, Redux, Redux-thunk I want to have an initial state through a server request (API call) but I cannot seem to get this to work.

What I have got so far:

var Redux = require('redux');
var carReducer = require('./reducers/cars');
var thunk = require('redux-thunk').default;

var initialState = require('./reducers/initialState');

var rootReducer = Redux.combineReducers({
    cars: carReducer
});

module.exports = Redux.applyMiddleware(thunk)(Redux.createStore)(rootReducer, initialState.loadInitial());

This is my initial store creation. My InitialState looks like this:

var $ = require('jquery');

module.exports = {
    loadInitial: loadInitial
};

function loadInitial() {
    return {
        cars: [
            {}
        ]
    }
}

When I try to turn this loadInitial into a $.get('api/...'), Redux tells me that I need an initial state in order for it to work.

In my reducer I have a load method:

function updateReducer(state, action) {
    switch (action.type) {
        case 'load':
            return action.data;
        case 'update':
            return updateCars(action.data, state);
        default:
            return action.data || initialState.loadInitial().cars;
    }
};

But again, if I use - as a default - an async call, it does not seem to work.

What I actually want is for my store to be initialized with whatever comes from the database. This is needed for my HandsonTable, since I pass the properties to the table and as I have it now, it will only render me one row because my initial state has only one object.

Weird part about this is that when I click on the table, it actually gets me all my rows because the data is loaded, but I'm guessing just too late.

Anyway, my question here is, how do I initialize my store through an api call to my backend?

回答1:

You can give it a blank initial state (empty object or perhaps just a loading message) and when your API call comes back, you can update the state and your component will redraw with its new data as a consequence. The other thing you can do is not initialize your component until the call returns with your data.

EDITED TO INCLUDE EXAMPLE

In one of your lifecycle methods of your component (perhaps even in getInitialState):

getInitialState: function() {
  var oThis = this;

  $.get({
    url: 'api...',
    success: function (...) {
      oThis.setState({...data returned by server});
    }
  });

  return {};
}

Or, something along these lines:

$.get({
  url: 'api...',
  success: function (...) {
    var oStore;

    // oStore = response from server

    ReactDOM.render(
      <ReactRedux.Provider store={oStore}>
        <MyComponent/> 
      </ReactRedux.Provider>
      , document.getElementById()
    );
  }
});


回答2:

For redux initial state you can't pass async value, so you need to pass some static empty object (like you have in your example) and call an action to get initial state from server and replace your state. To simplify all this process you can use redux async initial state middleware