Folder and files structure is something I have found on the matter of the opinion instead of a thing that rules it all.
Depending of the project there is minimal convention on how components are structured inside a project (spoiler alert, inside /components
folder and separation of container/UI components).
This time, I want to go to the space on how to structure a component itself.
I have created an opinion after working with several mid sized code bases.
TL;DR:
component-name/
├── index.js/ts
├── component-name.js/ts
├── styled-components.js/ts
├── component-name.test.js/ts
├── component-name.mapping.js/ts
Files, camelCase or kebab-case?
I use kebab-case naming style, GitHub by default is case insensitive, that means that changing HolaFolder to holafolder is not an actual change that it will recognise.
Also it's simpler to read by having one character that separates the world instead the cognitive load of capital letters vs lowercase ones.
The index file
This is the file that I use to expose the component.
Let's imagine that I have simple UI component that exports default.
// index.js/ts
export { default } from './example-component'
Or in the case of named exports:
// index.js/ts
export { openModal, closeModal } from './example-component'
We don't need to change the imports of any component in which we use the 'example-component'.
Implementation details, in the component-name.js/ts file
I have seen a lot a structure like this:
component-name/
├── index.js
In which index.js
has the implementation details of our component, the problem. While working and having 10+ tabs with the same name makes difficult to follow the file that I want to find.
For that reason I add the implementation on a file with the same name as the components' folder, to make easier to work with multiple files.
styled-components.js/ts
This is based on the fact that the last 3 years of my career I have been working in companies that used it.
Having a separated file for the components which responsibility is purely aesthetics make easier for:
- A designer that codes to tweak the components without the need to change the implementation file
- A developer to separate the concern of your components
- Insolate styles in a common pattern file which makes it easier to identify project wide
Tests
Having component-name.test.js/ts
is a common pattern, the difference is that I prefer to have the tests as close as the implementation, this so if the component is obsolete and we need to remove it, we remove it as a module, the contrary of having a special folder tree for tests, which can lead to broken (unused files).
Mapping and (component-name.***.js/ts)
Redux is a common library used for state management, but nowadays we have different solutions, and what we do is to "connect", or "map" certain props in our component to a store.
For that reason we created the component-name.mapping.js/ts
component.
// mapping component
const mapStateToProps = () => {}
const mapDispatchToProps = () => {}
export default connect(mapStateToProps, mapDispatchToProps)(Component)
In that sense if we have a component that in the future needs to be connected and we have the index.js
file that exposes our component, then is as easy to change it to:
export { default } from './component-name.mapping'
And not other components need to be changed.
Wrapping up
-
index.js/ts
: to expose the component -
component-name.js/ts
: components implementation -
styled-components.js/ts
: styled component (thanks capitan obvious) -
component-name.test.js/ts
: tests -
component-name.mapping.js/ts
: HOC or implementation to connect a component to a store
Top comments (0)