I am tempted to add error data to the store. For example,
var store = {
error: {msg:'',info:{}},
others: '',
etc: ''
}
On an error in the app, an action will update the error via the dispatcher, and the error panel will be shown to the user. The render of the error panel conditionally shows the div by testing the error msg state.
On the next user input, an action, i.e., userAction, the model state will be updated by the dispatcher. Problem: the error panel will still be shown, since the error msg state was not 'reset'.
The userAction will be setting other non-error state. Flux will emit a change for this change. Yet, if I follow the Flux model, a reset of the error should also be done here, in this action, but that would cause an emit, which tells to UI to update. Seems incorrect.
My thinking is:
1. Don't put this kind of stuff in the store? Or,
2. The store will reset the error state for every non-error update of state. Or,
3. Each action will also include an error state object for any state updates.
Currently my solution is to clear the error data within the store functions:
}, function(payload){
API.setError({msg:'',info:{}});
switch(payload.actionType){
case "BRANCH_SELECTED":
What is the non-idiotmatic way of doing this?
I'm new to React and Flux, so I'm sure this is newbie question. I'm using McFly as Flux implementation.
Though your question may have already been answered within the comments: I meditated on a similar question in my current React project and so I'm going to share my experience and outcome. I'm using fluxxor instead of McFly but that shouldn't matter here.
As flux stores should contain all application state and logic, I came to the conclusion that it's absolutely okay and in the sense of the flux architecture if you programmatically clear your error states conditionally within your store functions.
In my understanding it makes sense to keep error state handling related to a specific store within exactly that store (and therefore probably received and rendered by few listening components). As mentioned by #fisherwebdev, the store logic should determine the state of an error, specifically based on the action types it registered callback functions to. In your case, think of a BRANCH_SELECTION_ERROR type action being dispatched that causes error state to be set. On the other hand the BRANCH_SELECTED action type should always clear this state.
My concrete solution is in fact to call "private" store functions clearErrorMessages() or clearFormValidationMesssages() which simply clear state variables dependent on the actions being currently dispatched.
Global errors, i.e. errors that are somehow related to the application state like server communication timeouts, may go into some "appStore" and being updated or cleared in a comparable way. So e.g. router transitions may cause global error state to be cleared.
Related
Firstly, I'm not entirely sure what is the ## prefix in the actions which most third-party packages I've installed in my React/Redux app mean -- if they mean "private", then the answer to my question is obvious. I see them in the Redux devtools extension for Chrome.
In case it's just a scoping convention ##<package>/<action>, then I have a concrete question regarding actions in redux-form package. Actions are, apparently, not documented, so I'm not sure if I can safely use them in my reducers without worrying for breaking changes.
For more context in case my approach is completely wrong (still figuring out patterns): I want to remove the register form and present a success message after successful completion. redux-form dispatches an action of type ##redux-form/SET_SUBMIT_SUCCEEDED, with meta.form telling me that it was a form I named register. So I'd use it in my RegisterPage reducer to set a boolean isSuccess and use that to change the view.
If they are not explicitly documented I would consider them private and not use them directly. Even though it's not stated officially anywhere, the ## prefix often indicates private actions which shouldn't be handled by other reducer code. I think it originated from the ##redux/INIT_{random string} action (discussion about the naming can be found in this github thread):
In the new docs (#140) we should clarify that any actions prefixed
with ## are not meant to be handled. For example, you should never try
to handle ##INIT.
In the redux code itself the privateness is also explicitly stated:
/**
* These are private action types reserved by Redux.
* For any unknown actions, you must return the current state.
* If the current state is undefined, you must return the initial state.
* Do not reference these action types directly in your code.
*/
For your specific problem: you could provide a onSubmitSuccess function to the HOC and dispatch your own action to update your own reducer or you could directly depend on the redux form state and get this boolean flag via the hasSubmitSucceeded selector. Personally I think the second option is the better one because it doesn't introduce redundant state in your store - redux form already stores the information whether a form was submitted successfully, doing so on your own in another sub-reducer could lead to the two boolean values diverging unintentionally.
I have a sequential data collection app built with React and Redux. Right now, I have internal state for each page which has a form and when user clicks "Submit" button, I am dispatching the data collected in the state and updating my Redux store. Should I be dispatching an action on every key entered(debouncing) or should I store it in a local state and update Redux store at once?
Will there be a performance issue if I dispatch action to Redux store on every keypress since it is not an asynchronous call.
Well, the answer is: it depends.
Some argue that we loose some of the advantages of using a central store (like Redux) if you also have an internal state in the components. Like, if all your application state is just the redux store, storing the store, or the sequence of actions that lead to that store, will give you a complete picture of what was happening before maybe an error occurs.
I believe that is excessive. It is completely fine to store little stuff in your component's internal state, but there should be a well defined line.
In case of a form, you'd have controlled input elements, and you'll want a mechanism to submit the form with an action. It'd be necessary to have the contents of the form in the redux store.
One way would be to have the contents in an internal state, and only put them into redux form after a little debounce. But that has some edge cases. What if the user submits the form in the little debounce time? The form in the store is incomplete. Is thinking about all the edge cases worth it?
I believe just having the form elements controlled from the redux form is the simplest solution. The performance issue one would imagine is not really an issue. This is also what redux-form does (you can look at how that is implemented for inspiration).
I've been using Flux first and Redux later for a very long time, and I do like them, and I see their benefits, but one question keeps popping in my mind is:
Why do we decouple actions and reducers and add extra indirections between the call that will express the intent of changing the state (action) and the actual way of changing the state (reducer), in such a way that is more difficult to provide static or runtime guaranties and error checking? Why not just use methods or functions that modify a state?
Methods or function will provide static guaranties (using Typescript or Flow) and runtime guaranties (method/function not found, etc), while an action not handled will raise no errors at all (either static or runtime), you'll just have to see that the expected behavior is not happening.
Let me exemplify it a little better with our Theoretical State Container (TSC):
It's super simple
Think of it as React Component's state interface (setState, this.state), without the rendering part.
So, the only thing you need is to trigger a re-render of your components when the state in our TSC changes and the possibility to change that state, which in our case will be plain methods that modify that state: fetchData , setError, setLoading, etc.
What I see is that the actions and the reducers are a decoupling of the dynamic or static dispatch of code, so instead of calling myStateContainer.doSomethingAndUpdateState(...) you call actions.doSomethingAndUpdateState(...), and you let the whole flux/redux machinery connect that action to the actual modification of the state. This whole thing also brings the necessity of thunks, sagas and other middleware to handle more complex actions, instead of using just regular javascript control flows.
The main problem is that this decoupling requires you to write a lot of stuff just to achieve that decoupling:
- the interface of the action creator functions (arguments)
- action types
- action payloads
- the shape of your state
- how you update your state
Compare this to our theoretical state container (TSC):
- the interface of your methods
- the shape of your state
- how you update your state
So what am I missing here? What are the benefits of this decoupling?
This is very similar to this other question: Redux actions/reducers vs. directly setting state
And let me explain why the most voted answer to that question does not answer either my or the original question:
- Actions/Reducers let you ask the questions Who and How? this can be done with the our TSC, it's just an implementation detail and has nothing to do with actions/reducers themselves.
- Actions/Reducers let you go back in time with your state: again this is a matter of implementation details of the state container and can be achieve with our TSC.
- Etc: state change orders, middleware, and anything that is currently achieved with actions/reducers can be achieved with our TSC, it's just a matter of the implementation of it.
Thanks a lot!
Fran
One of the main reasons is that constraining state changes to be done via actions allows you to treat all state changes as depending only on the action and previous state, which simplifies thinking about what is going on in each action. The architecture "traps" any kind of interaction with the "real world" into the action creator functions. Therefore, state changes can be treated as transactions.
In your Theoretical State Container, state changes can happen unpredictably at any time and activate all kinds of side effects, which would make them much harder to reason about, and bugs much harder to find. The Flux architecture forces state changes to be treated as a stream of discrete transactions.
Another reason is to constrain the data flow in the code to happen in only one direction. If we allow arbitrary unconstrained state modifications, we might get state changes causing more state changes causing more state changes... This is why it is an anti-pattern to dispatch actions in a reducer. We want to know where each action is coming from instead of creating cascades of actions.
Flux was created to solve a problem at Facebook: When some interface code was triggered, that could lead to a cascade of nearly unpredictable side-effects each causing each other. The Flux architecture makes this impossible by making every state transition a transaction and data flow one-directional.
But if the boilerplate needed in order to do this bothers you, you might be happy to know that your "Theoretical State Container" more or less exists, although it's a bit more complicated than your example. It's called MobX.
By the way, I think you're being a bit too optimistic with the whole "it's an implementation detail" thing. I think if you tried to actually implement time-travel debugging for your Theoretical State Container, what you would end up with would actually be pretty similar to Redux.
Let's say component invoked an action and store tries to perform some operation but it couldn't, so store is trying to report the error back to view so user can be aware.
I can think of two options to handle this.
Have store emit an error event and then view components can listen to this event like they listen to change events and show the error to the user.
Store can add the error to the state object and fire a change event, then the the view components can check the error on the state objects and display error message accordingly.
Or is there any elegant way of handling this ?
Store normal and error informations in the store state is a better way to do that. In your scenario, you may need to show a error dialog or something else in order to tell user something is broken. That is, you have to rerender your components according to different states, so just put the error information in your store state and emit a change event.
Put everything which makes components change in the store state. That allows everyone to know your data flow easily and quickly.
Can Flux actions access stores? I recently got a code review comment asking me to pass a certain value in from a React component, instead of getting it from the store directly in the action. This would change Flux's data flow from this:
View->Action->Dispatcher->Store-|
^-----------------------------<
to this
View->Action->Dispatcher->Store-|
^------^----------------------<
It seems to me that, because all data changes are still going through the dispatcher, that the data flow still goes in the intended direction, updates are still atomic, annd the flow is still easy to reason about. Could there be any drawback?
An action can access a Store, but it should be a strict read-only operation.
Actions may want to yield a dispatch that is conditional on the content of a store and keeping track of what store content is required to perform the action is not the responsibility of the invoking component.