I am designing an application in react/redux and I am new to flux/redux and unidirectional patterns. I ran into a problem which I am not sure how to properly solve within a unidirectional architecture
I want to illustrate the problem with the example of a user registration form that might show up in different parts of the app. Please note that the core problem is about if and where to handle subcomponent completion events and the UserRegistration
is just an example.
Let's say I have a component UserRegistration
which will render as a form. This component will handle its own submit action which may include some asynchronous calls to a server endpoint and in the end should lead to a modification of the store/state (e.g. adding new user data).
The user flow is the following:
I want to include this UserRegistration
form in different places in the app.
Let's say I want to show the registration form based on a route /register
and after succesfully registering I want to route back to /
.
The intuitive thing for me to do (coming from a non-unidirectional world) would look something like this
function MyApp() {
const isRegisterRoute = //... somehow check if /register is active
return (
<button onClick={ () => { routeTo('/register') }}>register</button>
{
isRegisterRoute && (
<UserRegistration // handles actual registration internally (network calls and store modification)
onCompletion={ () => { routeTo('/' } } // pass completion handler which will route back to initial path
/>
)
}
)
}
This would solve the problem but I am wondering if having a callback for such a component with a complex flow is an anti pattern in a unidirectional architecture.
onCompletion
handler down the chain within my component so it gets executed once the registration is complete. This passing around of the handler does not feel clean as it leaks into a lot of places.On the other hand I don't want to handle the routing back to '/' inside the UserRegistration
component as the success route or action might be different depending on where I use it so I want that logic to be decoupled from the component.
What would be the appropriate/best-practice solution for the problem described above within flux?
It's not an anti-pattern as I don't see any data flow from sub-component to parent, like
<SubComponent onComplete={data=>this.setState({data})}/> // not good
reroute to another router is logic, the next router
is the property passed to UserRegistration
component, so it's the same as
<UserRegistration nextRouteOnComplete="/"/> // property
and handle routeTo
logic in UserRegistration.
A function can be dynamic, do make sure no data will be passed to the callback function, the callback is designed to handle logics after complete, no data should be passed, and data update should follow the unidirectional data flow,
dispatch action
-> reduce action
-> mutate state
-> rerender