Components
🟠 File structure
- ↕️ Imports
- 🎨 Styles
- 📜 Component constants
- 🛠 Component helpers
- 🆎 Component types
- 🎭 Component prop type
- 🍱 Component
🟠 Component structure
The following structure is just a recommendation, in fact it’s not even always possible to keep the same order inside a component. However, trying to be consistent really helps in the long run, especially when it comes to navigating larger components. It is also useful to group things within each category, e.g. the refs might not have empty lines between each other but if there is only one useDispatch better surround it with them.
- Redux selectors (aka global state)
useState(aka local state)- Non-effect hooks:
useRef,useForm,useDispatch, etc- This one is tricky. Consistency among the non-effect hook order is perhaps too redundant, although I would always put
useFormfirst, for example. Try to place them in the order of subjective importance.
- This one is tricky. Consistency among the non-effect hook order is perhaps too redundant, although I would always put
- Effects
- Functions / callbacks
- Values / components
- Render
Generally, it’s considered a good practice to not use optimisation techniques until you see that you need them. Also when it’s obvious from the start that something would require to be memo’ed – expensive calculation, frequent state updates, expensive re-renders.
Passing props to components
Whenever you pass props to a component, prefer passing only the parts that are necessary and avoid passing a whole large object of which only one or two properties are used.
It creates a clearer interface of the component (you can see right from the interface what is used). And it prevents unnecessary re-renders.
// good
const DeviceVersion = ({ version }) => <div>{version}</div>;
// bad
const DeviceVersion = device => <div>{device.version}</div>;
Prop drilling and identifiers
Don’t pass entire objects which have an identifier of some sort around in components too much. In simpler terms, consider the Redux store as the primary source for components to retrieve complete data. For instance, if you have three components (C1 ⇒ C2 ⇒ C3) and C1 receives an account key, if both C1 and C3 need the full account, they should use the selectAccountById selector to access it. C1 and C2 should only pass the accountKey as a prop to their children. This principle also applies to selectors, where the parameters should ideally be as granular as possible, like selecting something by id . This minimalistic approach simplifies the identification of what’s necessary in components, helps avoid unnecessary re-renders, and slightly improves performance.