Component Structure - laujonat/react-table-hooks GitHub Wiki

Component approach

Premise

Our current styling convention

  • BEM naming convention + CSS/SCSS styling. We are using the concept of DOM elements to describe the functionality and behaviors of the component.

What we want to solve

  • How do we make components reusable and DRY without adding complexity into current components?
  • How can we logically structure our files to avoid bloat (compare to current directory structure) such that related components follow a single responsibility.
  • Best practice to handle class specificity as classes become bloated and often have to overwrite global styles.
  • Naming convention is unclear. Class naming is often subjective between developers and requires a strict level of team adaptation and subject to interpretation.

In a BEM project, the team operates in terms of blocks, elements, and modifiers as a BEM Tree.

Principles behind BEM.

Modifiers

Modifiers will be used to express the logic of a block or element, in the same we have used modifiers to define an appearance for a certain state. Answers “What size, theme?”

Blocks

Blocks are functional independent components that are meant to be reused. Should answer the “What is it?” question. This would be equivalent to the class in HTML blocks. Using modifiers, the state of blocks can be set or removed.

Elements

Elements are the composite part of the block that cannot be used separately from the block. It answers the question “What is this?”

“Is this a block or an element?”

Create a block If section of code can be resused and does not depends on other page components.

Create an element If section of code cannot be used separately without the block (parent entity)

Take the following example for our we are currently handling styling:

    // BEM approach 
    <Button className="btn"></Button>
    <Button className="btn btn-primary"></Button>

In the above example, when you want to use the button you'd define the classname for both a button as well as a "primary" button, which may have styling to convey more importance.

But with components, we don't need these BEM classnames. These are implementation details, specific to the class names of the Button component.

Note: In order to use the button component, I would also have the use the button class. Having to extract the classname is redundant, as we already have the encapsulating component.

Here is a common approach in React working with a component that deals with Api fetching using BEM classnames.

class SectionContainer extends Component {

  componentDidMount() {
    fetch('api/endpoint')
      .then(res => {
        this.setState({items: res.items})
      });
  }

  render() {
    return (
      <div className="section">
        {this.state.items.map(e => (
          <div className="section__item item">{item}></div>
        ))};
      </div>
    )
  }
}

Here, a component somewhere in an application is responsible for fetching data from some API, then renders the items from the API.

Our component cares about two things: managing and fetching data, in addition to styling. (breaks Single Responsibility Principle)

Solution

  • BEM Javascript component approach with an OOP approach. We have the ability to avoid describing a class in DOM elements, rather we can utilize an abstraction of the a tree of components.

"A component should do one thing, and do it well"

Best Practices

  • Small, focused components
  • Use container components

To avoid such implementation details, a container and component approach has brought in the use of Styled Components. A common practice is to have a component such as the following:

Here is a component example:

class SectionContainer extends Component {

  componentDidMount() {
    fetch('api/endpoint')
      .then(res => {
        this.setState({items: res.items})
      });
  }

  render() {
    return (
      <Section>
        {this.state.items.map(item => (
          <SectionItem item={item}/>
        ))};
      </Section>
    )
  }
}

We've now separated the logic between managing and fetching data where our component now cares about data fetching, and now have a smaller components of Section and SectionItem, where the concern of fetching and passing data in the right format is separated.

Organizing our project with a modular approach

  • The approach for a project structure takes the following into account.

SMACSS Principles

Scalable css follows these 5 categories:

1. Base: Contains all general rules.
2. Layout: Define structural properties and sections of content (header, sidebar, content)
3. Module: Subcategories for various logical blocks of UI.
4. State: Defines modifier classes to indicate element states.
5. Theme: Contains color, font, and other cosmetic aspects that may be modifiable. 

This separation is easy to achieve using styled-components. Let's bring styled-components together with these principles.

Presentational/Container architecture

Presentational Components

  • Should not care about dependencies
  • They receive props, data, and render them accordingly.

Container Components

  • These are aware of data architecture. (state, redux, flux)
  • Not responsible for data is displayed
/ assets
- These are static served files such as images, svg files
/ components
- These are reusable components organized by feature. These are the blocks necessary for composition. 
/ shared
- Any commonalities among components can be separated here. This may included buttons, utility functions. 
/ styles
- Purpose is to keep all styles organized in a single directory.  If you want to add any custom attributes, look here first, and use the Theme Provider to bring in the attribute.
/theme
- Unified theming export file.
/views
- Composition layer. Can be divided between presentational and container components. 
App

Trade-offs

  • Learning to navigate this project structure will have a learning curve.

Theme Provider

References https://www.toptal.com/javascript/styled-components-library https://www.sitepoint.com/bem-smacss-advice-from-developers/ https://medium.com/styled-components/component-folder-pattern-ee42df37ec68 https://en.bem.info/methodology/js/ https://en.bem.info/methodology/js/#oop-principles-in-javascript-for-bem https://en.bem.info/methodology/block-modification/ https://tech.decisiv.com/structuring-our-styled-components-part-i-2bf21fa64b28 https://www.smashingmagazine.com/2018/06/bem-for-beginners/ https://github.com/carlosepp/reactomikit/ https://medium.com/fed-or-dead/battling-bem-5-common-problems-and-how-to-avoid-them-5bbd23dee319

⚠️ **GitHub.com Fallback** ⚠️