Search code examples
reactjsreduxcallbackurl-routingflux

how to handle subcomponent completion eventsin react / flux / redux


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:

  • user clicks on 'register' button
  • user sees registration form
  • user types in data and clicks 'submit'
  • user registration form disappears

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.

  • One concern is that the callback basically inverts the direction and it's no longer unidirectional.
  • Another concern is that I would have to pass the 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?


Solution

  • It's not data flow at all

    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