What most tutorials and courses overlook is how all the pieces come together into one application.
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
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} />
}
}
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 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>
)
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 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
}