ACE coding style guide
These are the rules and best practices that will be checked for ACE Designer in the pull requests.
React
Use React.FC
interface for components
Use React Functional
components via React.FC
interface, rather than Class
components.
Motivation
Using React.FC
interface for components guides the developer to return the proper React FunctionalComponent
structure.
While type inference works great, unless components built are actually used, this will trigger no warnings. It is also convenient to see warnings during component development, that returned structure is not correct, rather than to discover type error when writing the unit test.
Possible issue that is detected during compile/runtime
// no type check error
export const Example = () => "<></>"
Issue detected early on while constructing the component
// tsc detects, that returned type cannot be used by React
export const Example: React.FC = () => "<></>"
// as intended
export const Example: React.FC = () => <></>
Action handlers in React component props
Motivation
Code readability is better, when everything that is related to the particular function is located in the Component module.
When to pass action handlers in props
If component is reusable (for example FlowListItem
).
When to create action handlers in module
If component is not reusable (for example FlowList
).
React hooks
Use React Hooks to manage component state, apply effects.
Theme in UI Components
Use UI Theme colours, fonts, grid sizes for styling, rather than define them inline in the component style.
Redux
Redux hooks
Use Redux hooks to manipulate application state and retrieve information from application state.
Thunk error handling
await
dispatched actions and handle response (either by checking if action is rejected or .unwrap()
to throw exceptions.
If dispatched action is intended to be fire and forget, then need to add comment to indicate that.
Cypress
Waiting till element is found
Don't unnecessary wait in tests.
Note - though cypress typically waits till element exists chainable commands may not work.
cy.get("some-selector").contains("some text)
- in this example Cypress waits till it finds some-selector
and then
searches some text
, but if some-selector
is not unique and exists in page, then Cypress fails to wait till some text
appears.
One way to fix it is to use cy.contains("some-selector", "some text)
Storybook
Storybook actions
Use Storybook actions to handle events instead of console.log
Motivation
It allows to see actions immediately in Storybook without checking console
Javascript
Naming
Use camelCase.ts
for file names, unless it's ReactComponent.tsx
.
It's ok to use ClassName.ts
for files with Javascript class, though it's recommended to stick to camelCase
.
Motivation
Consistency across solution
Arrow functions vs functions
Motivation
This guide explains arrow function use cases and differences.
Performance vise Arrow functions are the same as regular Functions.
Use arrow functions when there is no intent to instantiate the Function with new operator or use Function instance scoped context (this
).
When to use Function
If developer wants to leverage the function context (this
) and imply that there will be multiple instances of Cache Singletons, that will use different cache instances.
function Cache() {
this.cache = new Map()
this.getCachedValue = (key) => this.cache.get(key)
}
When to use Arrow Function
If developer knows that there will be only one cache per module/solution.
const cache = new Map()
const getCachedValue = (key: string) => {
return cache.get(key)
}
lodash imports
Use specific module import to import lodash
methods.
Use
import foo from 'lodash/foo'
Don't use
import { foo } from 'lodash'
//or
import _ from 'lodash'
Application layout
- Generic components must stretch to the size of parent container.
- Generic components must not have margins and paddings beyond the need of cosmetic look.
- Application layout must be functional with screen width size of md (900px).