-
Prefer the usage of native methods, don't rely too much on lodash. Examples:
- We tend to over use isEmpty and there're many native ways to do it:
import { isEmpty } from "lodash-es"; /* When an array is present or does not have values */ const emptyArr = []; console.log(!isEmpty(emptyArr)) // output: false // same check using native methods console.log(Array.isArray(emptyArr) && emptyArr.length > 0) // output: false /* When a string is empty */ console.log(isEmpty("Hola")) // output: false // same check using native methods console.log(!!"Hi") // output: true /* When a object property is present or not */ const obj = { name: "Jean" }; console.log(!isEmpty(obj.surName)); // output: false // same check using native methods console.log(!!obj.surname) // output: false /* Checking an empty object is a bit harder though, so I would reccomend using the isEmpty method If you want to do it yourself: => isEmpty for objects Link: https://coderwall.com/p/_g3x9q/how-to-check-if-javascript-object-is-empty */
I would say in most of the cases that we think isEmpty is required, we should rethink how are we passing the props, how do we use the PropTypes and how we can improve the code to avoid the use of it (not saying we should not use it, but be smart on how to use it).
-
Don't pass the whole object as a prop if you're only using a few attributes of it Examples:
const visualization = {
// Lot of props
values: [1, 2, 3]
}
// Incorrect
<Score visualization={visualization} />
// Correct
const score = visualization.values[0] // Just an example, please validate if doing something like this;
<Score scoreValue={score} />
-
Avoid using
PropTypes.oneOfType([PropTypes.object])
, explicitly add all the attributes that will be used, this can be avoided if you pass props using rule number 2, but if you need to pass the full object, use this rule instead. Example:const Person = ({ person }) => { const { id, name } = person; return <div>{name} - {id}</div> } // Wrong Person.propTypes = { person: PropTypes.oneOfType([PropTypes.object]).isRequired, }; // Good (Help us to check which properties are needed for the component to work) Person.propTypes = { person: PropTypes.shape({ id: PropTypes.number, name: PropTypes.string }).isRequired, }; }),
-
Think twice when connecting a component to the redux store(You might have the prop in the parent or there's no need to connect it at all).
-
Connected components don't require a default prop declaration(for connected values), they will always have the values set in the redux state so you can set those values as required props in the component. Example:
const mapStateToProps = state => ({
loading: state.reducer.loading,
});
// Assuming that loading is a boolean value.
YourComponent.propTypes = {
loading: PropTypes.bool.isRequired
};
export default connect(mapStateToProps)(YourComponent);
-
Make components as dumb as possible: Examples:
// Good const Button = ({ content, onClick, btnStyles }) => ( <button className={btnStyles} onClick={onClick}> {content} </button> ); // Bad const Button = ({ content, onClick, btnStyles }) => ( <div className="viz container"> <div className="btn-container"> <button className={btnStyles} onClick={onClick}> {content} </button> </div> </div> )
The second example is tied to the div classNames, so the classes will need to be modified in every component where we want to put the button, we want this component to be easy to reuse and we need to make it pretty dumb, so the first option is better cause it will work on any given container.
-
Prefer React.Fragment instead of </> Open to discussion Examples:
<React.Fragment> <div>Hola</div> </React.Fragment> <> <div>Hola</div> </>
-
Prefer destructuring in the function parameters section instead of inside the function Open to discussion Examples:
const Person = ({ name }) => <div>{name}</div> const Person = (props) => { const { name } = props; return <div>{name}</div> }
-
Prefer the shorthand syntax of the arrow function if you're not doing anything before the return statement Examples:
// good const sum = (a, b) => a + b; // Bad const sum = (a, b) => { return a + b; }; // Good const weirdSum = (a,b) => { const firstNum = Number(a) * 100 + 50; const secondNum = Number(b) * 300 + 100; return firstNum + secondNum; }
-
Avoid mutating stuff unless is intended for some reason, react and redux will have strange behaviors if you mutate the state.
-
Keep in mind accesibility when working with custom components that act, but are not buttons, links or any other interactive html element. https://reactjs.org/docs/accessibility.html. The HierarchyBreadcrumb component is a good example of a component that uses a
<span>
tag that acts like a button