React Structure

What most tutorials and courses overlook is how all the pieces come together into one application.

Directory

The directory is subjective and varies per project, below is an example of a directory with a clear division of responsibility.

src/
    containers/
        HomeContainer.js
        AppContainer.js
        LoginContainer.js
    components/
        Header.js
        Greeting.js
        SignUpForm.js
        SignInForm.js
    pages/
        Home.js
        SignUp.js
        About.js
        Contact.js
        Dashboard.js
    services/
        SlerpApi.js
        GoogleMaps.js
    helpers/
        dateformatter.js
        validation.js
        scale.js

Parts

Containers

Containers are Class Components where most of your Application State lives, acting as a Parent Component where Props are passed from. This prevents your State from being scattered all over the place and makes it easier to find the source of data.

export default class AppContainer extends React.Component {
  state = {
    user: null
  }

  signIn = user => {
    this.setState({ user })
  }

  render() {
    return <HomePage user={this.state.user} />
  }
}

Pages/Screens

These are Stateless\Functional Components where you piece together Components into a layout, passing Props into said components. It's ideal to avoid displaying Props here. Sometimes you'll want to add logic which will affect the UI, e.g. Loading Component.

const HomePage = ({ user }) => (
  <div>
    <Header />
    <div className={CSS.body}>
      <Greeting name={user.name} />
    </div>
  </div>
)

Components

Components are where you feed Props into UI, and should be Stateless\Functional unless the use case requires State, e.g. Forms, Action Inputs.

const Greeting = ({ name }) => (
  <div>
    <h1>{`Welcome ${user.name || 'Guest'}`}</h1>
  </div>
)

Services

These are functions that connect your application to a backend or third party service, e.g. Slerp API, Google Maps API.

export const useSlerpApi = (directory, options) => {
  const url = `https://api.slerp.com/${directory}`
  return fetch(url, options)
    .then(res => res)
    .catch(() => {
      throw Error(`Can't connect to Slerp API!`)
    })
}

Helpers

Helpers consider splitting functions which are commonly used throughtout the application, e.g. Format Helper, Currency Helper

export const validateEmail = email => {
  const errors = []
  if (!email) {
    errors.push('Email Required')
  } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(email)) {
    errors.push('Invalid Email Address')
  }
  return errors
}

Reference