I am new to this project, and I am enjoying reading the code. But I am having a hard time figuring out how to add my app's (new) state to the store.
The specifics of my app is that my server.js code will receive data asynchronously from some other server, which needs to be reflected in the GUI.
My understanding of the Redux pattern is that my server code should create actions for each newly-arrived bit of information and then dispatch them to the store. The update in the store then propagates to the React containers/components that rely on it.
I realize that this might be more of a Redux question, but I would love to see an outline of steps for the following in react-redux-universal-hot-example:
{ type: xxx, ... })Thanks!
Add new state is simple! Just write your own state file under redux/modules/, here is part of mine schedule.js:
// define constants for different actions
const UPDATE = 'uhs/schedule/UPDATE';
const UPDATE_SUCCESS = 'uhs/schedule/UPDATE_SUCCESS';
const UPDATE_FAIL = 'uhs/schedule/UPDATE_FAIL';
const SEARCH = 'uhs/schedule/SEARCH';
const SEARCH_SUCCESS = 'uhs/schedule/SEARCH_SUCCESS';
const SEARCH_FAIL = 'uhs/schedule/SEARCH_FAIL';
// initial state object, your may put more initial object here if needed
const initialState = {
loading: false
};
// this will be used to `dispatch` actions, each `case` condition deal a kind of `action`
export default function reducer(state = initialState, action = {}) {
switch (action.type) {
case UPDATE:
case SEARCH:
return {
...state,
loading: true
};
case UPDATE_SUCCESS:
return {
...state,
loading: false
};
case SEARCH_SUCCESS:
return {
...state,
loading: false,
searchResult: action.result.data
};
case UPDATE_FAIL:
case SEARCH_FAIL:
return {
...state,
loading: false,
error: action.result.error
};
default:
return state;
}
}
// internal actions here
function _updateSchedule(data) {
return {
types: [UPDATE, UPDATE_SUCCESS, UPDATE_FAIL],
promise: (client) => client.post('/schedule/update', {data})
};
}
// this show how to `dispatch` sequential actions, See `clientMiddleware.js`
export function updateSchedule(data, callback) {
return (dispatch) => {
dispatch(_updateSchedule(data))
.then(callback);
};
}
// your action here, if it may have multiple `type` of result, use `types` field;
// note `post` (`data`) & `get` (`params`) has different arguments. See `clientMiddleware.js` under `redux/middleware` for detail
export function searchSchedule(params) {
return {
types: [SEARCH, SEARCH_SUCCESS, SEARCH_FAIL],
promise: (client) => client.get('/schedule/search', {params}),
};
}
@richb-hanover
Then import your js (for me, it's schedule.js) into reducer.js under redux/modules just like other modules.
@richb-hanover,
Each reducer is responsible for a branch of the tree. The state object which is passed into reduce is just that branch, so everything stays separate. There is no formal declaration needed. Just fill that object with the data needed to render the parent and child components.
As you said, actions are straightforward. The methods in the reducer are action creators. All they do is return an action object with a unique type value. You may add whatever other data is necessary to update the state when action is handled.
Dispatch and connect are a little more tricky, and I'm not the best person to explain them. If things are connected correctly, then your component can just call the action creator and the action is automatically dispatched for you. If you find that your action is not happening, make sure connect is being called or else manually dispatch the action.
When I first started working with this, the docs for react-redux and the other redux libraries confused me. I got pretty far just mimicking the pattern in this project and blindly hacking when things didn't work. Gradually I got more comfortable with the pieces and then revisited the API docs.
Good luck!
Thanks for these hints - they were very helpful.
re: connect() function: the discussion on http://redux.js.org/docs/basics/UsageWithReact.html helped me figure it out. connect() takes two functions as arguments:
I had to read it a few times, but now it makes sense. As I understand it, when dispatch() is called, it uses those two functions to prepare all the props for the wrapped component
Another bit of information that I was missing... Sometimes my reducer got the full state from the store, other times (in other projects), it only got a slice of data from the store. (That was the genesis of my original question...)
I re-read the Splitting Reducers section (once again) at http://redux.js.org/docs/basics/Reducers.html#splitting-reducers and realize that each combined reducer gives a name to a property/property-sub-tree that becomes part of the state. If you use combineReducers(), _that's_ the part of the state that is passed to your reducer. (And I believe if you don't use combineReducers(), your reducer gets passed the entire state of the store.)
@richb-hanover That's correct. You can also nest usages of combineReducers to further isolate the segments of state that are passed into reducers E.G.:
combineReducers({
entity: entityReducer,
otherEntity: combineReducers({
subdomain1: subdomain1Reducer,
subdomain2: subdomain2Reducer,
subdomain2: subdomain2Reducer,
})
});
so that subdomain#Reducer will only receive the state slice corresponding to itself, rather than the state at otherEntity
@tearsofphoenix Your Suggestion worked perfectly for me . Thanks.
@tearsofphoenix Your suggestion worked perfectly for me as well. That kind of answer really rocks 馃
Most helpful comment
Add new state is simple! Just write your own state file under
redux/modules/, here is part of mineschedule.js:@richb-hanover