Nona Blog

Thoughts on what to do with abstracted child components

I have, for probably longer than would seem normal to any sane person, been pondering what to do with the uncommon stateless components one usually finds when refactoring or cleaning up components.

The common ones, like <Button />, <Header />, etc, would usually go into a common/components folder (or similar). However, I often enough run into components that would make for cleaner code if abstracted out but aren’t common enough for the common folder, or are initially too tightly coupled to the parent to be moved too far away.

A current example

I have some text with two text ‘links’, but they both go to the same flow. Create or reset your password. It also needs to track analytics and so there’s a fair amount of reused code, where the only thing that really changes is the label Create / reset.

Current patterns

To set the stage, our standard app structure usually looks something like this:

src/
  common/
    components/
      Button/
      ...
    utils/
    ...
  modules/
    App/
      App.js
      App.styles.js
      App.utils.js
      App.utils.test.js
      ...
    AnotherModule/

A pattern I’ve adhered to in the past, is a hardline – throw EVERYTHING stateless into src/common/components (sometimes common/modules), with all stateful components going in src/modules/.

Another approach and one we’ve taken in current projects: all common, reused stateless components go in src/common/components, but any stateless component abstraction within a stateful component (and to a lesser degree, larger stateless component), would go inside the component before the render, declared as a standard const:

const SomeComponent = ({}) => {
  const ChildComponent = ({}) => {
    return(...)
  }

  return (
    <div>
      ...
      <ChildComponent />
      ...
    </div>
  )
}

In my example above, I ended up pulling the Link component into the body before the return(…) (opt 2) – but it should really go somewhere else. As it’s only used within the SignIn form at the moment, I really don’t think it makes sense to move it to a common folder just yet.

Proposals for a better solution

Option 3: Pull the components out of the stateful/parent component, but nest them alongside the parent with a <Module>.components.js file. I’m currently actually leaning towards .children.js.

//Example:
src/
  modules/
    App/
      App.js // <= this would be the parent component
      App.children.js // <= all components would go here
      App.children.styles.js // Styles for components
      ...

Option 4: Put all child components into a components (or children) folder as separate components alongside the parent Module like so:

//Example:
src/
  modules/
    App/
      components/
        SomeChildComponent.js // <= all components would go here      
        SomeChildComponent.styles.js
        AnotherChildComponent.js
        AnotherChildComponent.styles.js
        ...
      App.js
      ...

Conclusion (of sorts)

I’m a little torn between the two options. Option 3 keeps the file structure as shallow as possible, and all children are in the same place. However Option 4 sticks closer to the 1 ‘class’ per file rule of OOP, which I think translates well to components and I generally try stick to 1 component per file myself. It also probably makes it slightly easier to move these components into the common folder when the time comes (but either way with modern IDEs this is trivial).

Honestly for the most part I keep them nested inside the parent component along with all the other variables, hooks, callbacks, booleans, etc, unless it really gets out of hand, but I’m trying to move towards cleaner, smaller chunks of code with all the ‘helper’ bits of logic and components extracted into separate files, which makes everything easier to read.

/Ends.

Anyone have thoughts/preferences? HMU in the comments 🙂

Nona helps funded businesses accelerate their software projects. If you’d like to soundboard your tech project or your development team, book a consultation with us and we can chat through it! 

Avatar

Cam Olivier

Senior UI Developer - Nona

Add comment