salsita / prism

React / Redux action composition made simple http://salsita.github.io/prism/
496 stars 24 forks source link

Sibling components interaction best practice #62

Closed dvshur closed 6 years ago

dvshur commented 7 years ago

Hi guys,

so I was wondering, what is the best practice for making sibling components interact with each other? Imagine I have two components in different branches of a state tree: a form and a button (the button is somewhere else on the page outside the form), and I need, for example, to validate the form on a button click. Like this:

2016-10-17 10 34 34

So far i’ve come up with 2 possible solutions.

The first one is to export an updater-like function from the Form updater.js file along with init and Updater, something like

// Form/updater.js

// export const init...

export const setFormUnderValidation = (state, ...someArgs) => newUnderValidationState

// export default new Updater...

then import it in the parent component updater and use whenever I need to modify the Form validation state. In this case I can store an underValidation flag in the Form model itself and modify it whenever necessary with an exported setFormUnderValidation function. Hovewer, I don't like this approach very much, since if there were to appear more updater-like functions, it would break the whole Updater paradigm (and some practical disadvantages as well, like much less testable and mainteinable code).

The second way would be to store a formUnderValidation flag in the parent component instead and pass it to the Form component in a prop. Like this:

// Parent view
<div>
    <Form underValidation={model.formUnderValidation} />
    <Button onClick={dispatch('Submit')} />
</div>

// Parent updater
    .case('Submit', ...)    /// set formUnderValidation true

// Form view
    // ...
    componentWillReceiveProps(nextProps) {
        if (nextProps.underValidation) { dispatch('Validate') }
        // 'Validate' is a form action to make it validate itself
    }
    // ...

It looks better in a way that it doesn't break a single-Updater paradigm, but is kinda counterintuitive. You give away some control over an object state to its parent, losing some of the component state encapsulation. Moreover, dispatching an action in a lyfecycle method right before render will trigger model update again, which in turn will trigger rerender, breaking a usual rerendering flow.

Could you guys gime me some advice on how to handle this scenario? I think I might be missing some third magical option that would look and feel just right.

stratospark commented 7 years ago

@dvshur This looks like the perfect place for redux-saga. Look into some of the examples

Basically, your parent component Updater should be attached to a saga. This saga can takeEvery action dispatched clicking the submit button, then handle that in a sub-saga. Inside that sub-saga, you can dispatch the form validation, wait for a response, then dispatch success or error actions. Your reducers can listen for these actions and update your UI state accordingly.

Hope this puts you on the right track.

dvshur commented 7 years ago

Inside that sub-saga, you can dispatch the form validation

@stratospark, but parent component sagas (and the updater as well, for that matter) only have access to parent component actions, while Form 'Validate' is a Form action. Child component's actions are supposed to be encapsulated in a child.

In this case I rather need a way for a parent component to affect the child's state (upon receiving its 'Submit' action on button click)

biirus commented 7 years ago

@stratospark there is some cons.

There is a good article about components communication https://facebook.github.io/react/tips/communicate-between-components.html. I do prefer props-callback style, but it don't solve sibling communication.

tomkis commented 7 years ago

Elm is all about top-down hierarchy approach, so yes probably the right Elmish approach would indeed be moving the state information up to the parent.

tomkis commented 7 years ago

Even plain React explains that pretty-well https://facebook.github.io/react/docs/lifting-state-up.html

q13 commented 6 years ago

Need more approach