Is it anti-pattern to call child component's method from Parent in react and why?
Asked Answered
F

2

6

I am trying to implement a specific Wizard component which user can consume using the pattern below.

<Wizard {...wizardProps} onFinish={this.handleFinish}>
    <WizardStep onValidate={() => this.componentARef.isValid()}>
        <ComponentA onRef = { ref => (this.componentARef = ref)}/>
    </WizardStep>

    <WizardStep onValidate={() => this.componentBRef.isValid()}>
        <ComponentB onRef = { ref => (this.componentBRef = ref)}/>
    </WizardStep>

    <WizardStep onValidate={() => this.componentCRef.isValid()}>
        <ComponentC onRef = { ref => (this.componentCRef = ref)}/>
    </WizardStep>
</Wizard>

Now considering the react way we can't/shouldn't call child component's method from parent component. Here I want to keep a isValid method in each component which will be called from Parent Wizard component on click of Next/Finish button. React way suggest to move the state and logic to parent component. But that way I won't be able to reuse the same component e.g. ComponentA in any other wizard or any other place or I will have to duplicate the validation logic in every parent component who is using ComponentA. Using ref or this approach I can easily access the child component's method(isValid).

As of today(React version 16.6) I don't see any pitfalls using this pattern on need basis in react. What are the possible problem I may face using this pattern in react? And is there any better option in this particular example using which I can keep isValid method in step component(e.g. ComponentA) for reuse?

Forbidding answered 12/1, 2019 at 12:7 Comment(4)
it is technically accepted that you should use a top-down, decoupled approach to component design and data flow within React, so yes, with that in mind, it is an anti-pattern to call child methods in the parent.Accomplished
why can't you turn the Next/Finish button into a reusable component that each of your components then consumes? that way, each component has control over that button (i.e. disabling it as necessary), and you can still have your whole wizard form flow intact.Accomplished
yes, I understand that considering react paradigm it's not advisable. But like in this scenario when I'm trying to abstract out the logic of ComponentA along with it's validation it seems to be pretty obvious and straight forward. I am just trying to understand does this term AntiPattern comes with any disadvantages/pitfalls which I may face later.Forbidding
prev/next/finish button is already a reusable WizardFooter component. But I don't want to include it in my stepComponent(say ComponentA) because then I won't be able to use that form/component at some other place where I probably need a different action e.g. form submit button.Forbidding
H
6

Short answer

Yes.

Long answer

From React's doc on refs:

In the typical React dataflow, props are the only way that parent components interact with their children. To modify a child, you re-render it with new props.

Your first inclination may be to use refs to “make things happen” in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy.

Refs were created to access the DOM in specific use cases (focus, text selection, media playback, third party libs, etc), but they shall be avoided when trying to make other components execute actions.

So of course you can have a React app that works while using refs to call child component method, but yes, it is very anti-pattern.

Henry answered 12/1, 2019 at 12:21 Comment(1)
I have read these exact lines, I always follow this ideology and in most of the cases I use state than refs(e.g controlled components ). But in this scenario, one important thing is I'm not updating the child component rather I'm reading the state or state derived value and the solution seemed perfect to me eventhough it breaks react guidelines. In my question I was mostly interested in why part and better solution for the given example if any.Forbidding
U
1

Short Answer: This approach in your scenario is alright. Just re-visit it when your scenario get change.

Explanation:

It's not an anti-pattern in your scenario. It will be consider an anti-pattern, if you are controlling behavior of child component through ref.

React suggest to avoid such anti-patterns as general advise to avoid edge cases where your component become unstable as it get controlled by different source of truth. But, in the scenario like yours where you are sure about why you are using it, it's fine.

For example, React advise not to populate state from props. This is true because then you have two source of truth and you need to sync them otherwise your component will not behave properly. But, If you are sure that, your props (specifically data) will not be going to change, it's no longer an anti-pattern because, you are now seeding state from props but then it continue to manage at state level only.

Unijugate answered 24/1, 2019 at 8:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.