# ๐ Utopian React App
This doctrine is a collection of experienced approaches to authoring a React app.
## General Rules
1. ๐จ [Only use named exports](https://dev.to/n8io/developer-dark-arts-default-exports-31ia)
2. ๐ค Only `export` at the end of a file. Do not sprinkle them throughout the module like Hansel and Gretel.
3. ๐จ Only use arrow functions
4. ๐ฉโ๐ Only use functional React components. [Death to class components](https://dev.to/n8io/developer-dark-arts-react-class-components-3g8j).
5. ๐งช Spec files should be colocated to the implementation (and suffixed with `.spec.tsx`)
* No `__tests__` directories
* No `.test.tsx` suffix
6. ๐ค Only export from a module when there is a use case
7. ๐ท๏ธ Import types via `import type { } from ...` syntax when possible
8. ๐๏ธ If a component/data/util is used by multiple parents, move it up to a common parent directory
9. ๐ฃ All data requests should be made via `hook`
10. ๐ทโโ๏ธ Shared state should be shared via `Context` and accessed via `hook`
11. ๐ซ React components should always be in the form of a `ProperCased` directory with child `index.tsx` and `index.spec.tsx` files
* _All other file & directory names and should be `camelCased`_
12. ๐ฅ React component files should contain only one component. Large components are fragile and hard to test.
13. ๐ You should always use a `react-router-dom` `<Link/>` for all links
14. โจฑ A variable name should never start with an underscore (`_`). The exception being that you want to keep an unused, positional function parameter as a placeholder to maintain readability.
```typescript=
// For example...
const removeUserMiddleware = (_request, response, next) => {
response.body.user = undefined
next()
}
```
11. ๐ก [Alphasort all the things](https://dev.to/n8io/developer-dark-arts-ralpha-sorting-c0o): destructured object keys, component props, imports, enum values, oh my! _If we have our linting/styling setup properly these will sort automatically when saving a file_
12. ๐งถ [No magic strings/numbers](https://dev.to/n8io/developer-dark-arts-magic-strings-2ihn). These should be contained in an aptly-named variable(s) prior to consuming them.
## Testing
### Unit Tests
1. We should aim for 80% coverage
2. There should only be one snapshot test and it should be representative of the happy path of a component. Other conditional rendering should be tested using other means. E.g. `data-testid`'s or triggering events.
3. Snapshot tests should be inlined (via `.toMatchInlineSnapshot()`) _AND_ short (less than ~100 lines)
4. Where possible, child components should be mocked
* Reduces the snapshot size
* Promotes separation of concerns
* Focuses tests to the given component's unit of work
### End to End Tests
In an ideal world, **a feature should have at least one test**, possibly many more depending on its complexity. Good E2E tests should be checking if a particular set of interactions has a resulting outcomes that cannot be tested reliably by unit test. Their pass/fail outcome should answer the question "Is this feature working as expected?"
## Project Structure
### ๐๏ธ Root Directories
#### `components`
The place for React components that are shared across multiple modules. One directory per component, possibly with nested child components.
#### `constants`
Where you will find `enum`'s and frozen objects that are shared across multiple modules. One file per.
#### `hooks`
Where you will find all hooks that are shared across multiple modules. One directory per.
#### `modules`
1. Each module directory represents an app page/view (excluding `App`)
2. Each module should have a `Routes/index.tsx` that controls top level and child routing
1. This is where you might see child route lazy loading if needed
3. Each module should export, at minimum, the `Routes` component
Note: A general rule of thumb, if it is used across multiple modules, it needs to be elevated to a top level directory
##### The `modules/App` Directory
This special module is needed to setup top level providers, contexts, styles, routing, and config. It is the entry point of the React app.
#### `types`
A place for types that are shared across multiple modules. One file per _logical model_. Multiple types can live in a single file so long as they share the same model/namespace.
_NOTE: Don't forget, `enum`'s should live in `constants`_
#### `utils`
The home of shared utility functions that are shared across multiple modules. One directory per.
### ๐ธ Child Directories
Common child directories you _might_ see in `components` and `modules` root directories...
1. `components`
2. `constants`
3. `hooks`
4. `types`
5. `utils`
6. `Routes` - The component that controls nested view routing
Note: These directories should only contain items that are scoped to the given module/component
### Import Aliases and Relative Pathing
As a convenience, most projects allow aliased imports to avoid import statements with runaway relative paths.
```typescript=
// โ
import { thing } from '../../../../omg/make/it/stop/util/thing'
// โ
import { thing } from 'util/thing'
```
While this makes things much more readable, you can get yourself into trouble if you're not careful.
#### TLDR;
* If you are importing something **within** the current module, use the relative path (e.g. `'../../../util/thing'`).
* If you are importing something **outside** the current module, use the aliased path (e.g. `'util/thing'`)
#### The Long Story
The `modules` root directory is a logical boundary between the "public apis" of each module. Each module's `index.tsx` should define all that is publicly accessible.
```typescript=
// Given this...
// modules/otherModule/util/index.tsx
const util = () = '๐'
export { util }
// modules/otherModule/index.tsx
export { util } from './util'
```
```typescript=
// โ Don't do this
// modules/moduleA/Thing/index.tsx
import { util } from 'modules/otherModule/util'
```
```typescript=
// โ Do this instead
// modules/moduleA/Thing/index.tsx
import { util } from 'modules/otherModule'
```
There are a few reasons why we would choose to follow this convention.
1. At a glance it should be easy to know what other modules might be using from the current module by simply opening up the module's `index.tsx` and reviewing the `export`'s therein.
2. Implicitly this helps us avoid and/or identify circular dependencies when they occur.
* For example, `moduleC => depends on moduleB => depends on moduleA => depends on moduleC` is easier to reason about when there is a single entry point for each `module`
* Circular dependencies are notoriously difficult to troubleshoot and can be easily avoided when we follow this rule.