I'm currently not happy with the hacks I've come up with using Flux, and now Redux for populating initialState in my store.
I always send a payload of JSON down with the initial page load. Universal JavaScript is not an option in some of my applications as they are not all backed by Node. I would like to focus on "best practices" and patterns around how the data is preloaded on the client. Then, I feel that moving to the server is trivial.
Here’s a gist of what I’m currently doing at work and in a few other toy apps using Redux:
https://gist.github.com/kevinold/5767bb334472b7e2bfe3
To summarize:
This works and there aren’t any issues that we’re running into, but it feels like a hack I’m not really happy with. Also, I feel that the initial state of Redux isn’t happy with me doing it this way.
According to http://rackt.org/redux/docs/recipes/ServerRendering.html and the section “The Client Side”, I am able to pass initialState to my store.
Here’s a patch I have for another project I'm helping with (KeystoneJS). I'm passing it's Keystone object into the initialState:
https://github.com/kevinold/keystone/commit/6f80c2f6f1e5c081361369a8bb31b75f1e62460f#diff-cd8e9933209e834b0519a0257bcfa914R8
While that does work, as you can see, I’m forced to match the shape of the output of my overall combinedReducers (https://github.com/kevinold/keystone/commit/6f80c2f6f1e5c081361369a8bb31b75f1e62460f#diff-b4b498ca92c4d05e050b45c725c26f9d) or I will get console warnings, etc.
I might be extremely lazy in dealing with this, but trying to limit having to update another piece of data when I add/change anything related to reducers (add a reducer, how they are composed, etc.).
I realizing I might have to in order to get this initialState into the reducers properly.
I'm currently digesting how (https://github.com/erikras/react-redux-universal-hot-example/blob/master/src/client.js#L25) handles it's initialState.
I’d really appreciate some feedback on "best" and "real world" practices that are working for others.
There are two main ways to initialize state for your application. The createStore method can accept an optional preloadedState value as its second argument. Reducers can also specify an initial value by looking for an incoming state argument that is undefined , and returning the value they'd like to use as a default.
A Redux store doesn't have a limit on the amount of data stored, so you can pretty much use it to store almost anything, including bulky JSON data, data in table form, etc.
Some users prefer to keep every single piece of data in Redux, to maintain a fully serializable and controlled version of their application at all times. Others prefer to keep non-critical or UI state, such as “is this dropdown currently open”, inside a component's internal state. Using local component state is fine.
[preloadedState] (any): The initial state. You may optionally specify it to hydrate the state from the server in universal apps, or to restore a previously serialized user session. If you produced reducer with combineReducers, this must be a plain object with the same shape as the keys passed to it.
Manage the application state using redux store when it is global state. Try to avoid using setState in your component when you are using state management libraries like redux. Use component state when it makes sense ie. A Button component that shows a tooltip when hovered would not use Redux. Avoid Doing this.
In the majority of scenarios, the end-user does not know, and does not care whether Redux is used within the application at all. As such, the Redux code can be treated as an implementation detail of the app, without requiring explicit tests for the Redux code in many circumstances. The general advice for testing an app using Redux is as follows:
Let’s create an application in react with redux and set the initial state there: Step 1: Create a React application using the following command: Step 2: After creating your project folder i.e. example, move to it using the following command:
If you prefer, or are otherwise required to write unit tests for your action creators or thunks, refer to the tests that Redux Toolkit uses for createAction and createAsyncThunk. Reducers are pure functions that return the new state after applying the action to the previous state.
I don’t fully understand the question but I’ll try my best to answer.
In componentDidMount() I'm dispatching actions that “receive” and handle the various pieces of data. (These “receive” methods are used when processing these bits of data when they are fetched async via a request action, and I’m repurposing them here since I already have the data.)
This is a bad place to dispatch them. If you choose to dispatch actions instead of prodiving initial state directly, do that before rendering. In other words, do that right after creating the store! This way you don’t render the initial blank state.
While that does work, as you can see, I’m forced to match the shape of the output of my overall combinedReducers (https://github.com/kevinold/keystone/commit/6f80c2f6f1e5c081361369a8bb31b75f1e62460f#diff-b4b498ca92c4d05e050b45c725c26f9d) or I will get console warnings, etc.
You’re not supposed to create the initialState
object manually. You’re supposed to create a Redux store on the server, dispatch
actions there to prefill it with data, and when it’s ready, call store.getState()
to retrieve the state you want to pass down to the client. On the client, you’d read it from a global variable, and create the client store instance with it. In other words you never have to manually create initialState
—you’re supposed to grab it on the server with store.getState()
, pass it to client, and create a store with it.
Therefore I don’t understand the problem you describe. If your reducer names or nesting changes, it will change on the server too. There is nothing you need to do to “fix it”—if you use Redux both on client and server, their state structure will match.
I’d really appreciate some feedback on "best" and "real world" practices that are working for others.
If you use Redux on server, prefill the store as described above, and pass its state down to the client. In this case you need to use the initialState
argument of createStore()
.
If you for some reason don’t use Redux on server but you want to prefill the data anyway (e.g. maybe you use something other than Node), the approach with dispatching actions is your next best bet because it doesn’t require your backend to know the state shape. In this case, you should pass those actions as JSON to the client, and dispatch()
all of them right after the store is created.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With