10

Currently I have a class component that contains functions that act as components in my JSX.

Example:

class MyComponent extends React.Component {
    MySubComponent = (props) => {
        if (props.display) {
            return <p>This text is displayed</p>
        }
    }

    render() {
        return (
            <this.MySubComponent display={true} />
        )
    }
}

Are there any repercussions to calling components this way? Also is there a term for this?

CodingMadeEasy
  • 2,257
  • 4
  • 19
  • 31
  • 1
    There would only be a benefit for this if you are using `this` inside of that functional component. Otherwise there is not need to dynamically create it. Note that because you are using the property initializer syntax your functional component will be recreated for every instance of the class based component. – trixn Dec 06 '18 at 18:00
  • What was the reasoning for this? If there's none, you're writing more complex code than you could. – Estus Flask Dec 06 '18 at 18:00
  • @estus I would like the render function to remain declarative. So I've moved all render logic to functions to avoid having them inside the render function itself. I know I could easily call the function like this {this.mySubComponent()} but imo keeping it as JSX makes it easier to read. – CodingMadeEasy Dec 06 '18 at 18:04
  • I see. At this point MySubComponent doesn't need to be a part of MyComponent, according to KISS principle. Components can be used and tested separately. – Estus Flask Dec 06 '18 at 18:12
  • @estus I would usually agree, but this component is only going to be used by this class. It really is just a class function, it's just how it's being displayed which is in dispute. – CodingMadeEasy Dec 06 '18 at 18:14
  • Then this would be just a function that isn't used anywhere but current component. It's the same thing but also more efficient and also requires no additional actions if MyComponent would be refactored to functional component in future. That's why I mentioned KISS. If more complex solution doesn't provide benefits, it isn't needed. – Estus Flask Dec 06 '18 at 18:20

1 Answers1

15

This results in creating new MySubComponent function for each MyComponent instance, which is not very efficient way of doing this.

There may be only two benefits of having MySubComponent as MyComponent method.

One of them is that MySubComponent can be replaced with another implementation in MyComponent subclass without modifying render function. This isn't idiomatic to React because it promotes functional approach instead of OOP.

Another is that MySubComponent can access MyComponent instance and its properties. This results in design problem because two components are tightly coupled.

Neither of these arguments is substantial in React development. Unless there are specific needs that require MySubComponent to be a part of MyComponent, the former shouldn't be defined as instance method of the latter. It could be just:

const MySubComponent = (props) => {
    if (props.display) {
        return <p>This text is displayed</p>
    }
}

class MyComponent extends React.Component {
    render() {
        return (
            <MySubComponent display={true} />
        )
    }
}
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • 1
    What about the cases when they should be tightly coupled? For example, if we didn't have this function / component the render method would look something like this render() { return ( {true &&

    This text is displayed

    } ) } which isn't declarative.
    – CodingMadeEasy Dec 06 '18 at 18:19
  • It seems like there are only 2 alternatives which is: 1. Make the render function imperative or 2. Create a bunch of external functional components to ensure the render method remains declarative. Also method 2 works as you've stated, it seems to be counter-intuitive because the component is just made to make the core component "cleaner" so having it outside of the class doesn't really make much sense in my point of view – CodingMadeEasy Dec 06 '18 at 18:23
  • 1
    What cases do you mean? By tight coupling I meant that `MySubComponent` could use parent component instance, e.g. `this.state`, and this would be a design mistake. '2' is the way it's usually done in React. I'd say OOP paradigm works against you. You don't need to put everything you can into a class just to designate that an item 'belongs' to it, that's antipattern. Classes aren't glorified namespaces. There are already modules that work as namespaces. I'm a proponent of OOP where it's suitable but at this point its use is not justified at all. – Estus Flask Dec 06 '18 at 18:27
  • You make good point, but I do have one more question in favour of the OOP approach. Would {this.MySubComponent()} be any different than ? If so, why? – CodingMadeEasy Dec 06 '18 at 18:38
  • Since both components are at your control, that's ok, otherwise this would be a hack. In this specific case there's no difference in production. As for development they will appear differently in React devtools, and direct call may be less straightforward to test. `{MySubComponent({ display: true })}` is faster but if you do this just for performance reasons without an evidence that it's needed, this can be considered preliminary optimization. I used this only for workarounds. See https://stackoverflow.com/questions/52047063/direct-call-of-a-functional-component for some ideas. – Estus Flask Dec 06 '18 at 18:48
  • Sorry I'm a bit confused with your reply. So if I call the function directly as a function. Does it operate any differently behind the scenes as opposed to calling it as a jsx component? For example if {MySubComponent({ display: true })} is faster than why is it faster? And if {MySubComponent({ display: true })} is faster, is it any different than making the component outside of the class as you stated in the answer? Just want to know the overall differences between the two (if there is any) – CodingMadeEasy Dec 06 '18 at 18:54
  • 1
    Direct call is faster because it skips React element abstraction, basically `React.createElement` call and its rendering. React renderer calls a function internally any way. React elements are fast enough to not be a bottleneck. – Estus Flask Dec 06 '18 at 19:01