React best practices and patterns to reduce code - Part 3
Tags: react, reactnative, javascript, redux
Published: 2022-03-20 17:30:43

[![React best practices and patterns to reduce code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9qfo68lckofw16nfgp16.png)](https://www.youtube.com/watch?v=Y85X4PiuuTM)

This is 3rd the article about React best practices, If you have not read my previous articles, please check them out.

###### [React best practices and patterns to reduce code - Part 1](https://dev.to/devsmitra/react-best-practices-and-patterns-to-reduce-code-2bff)

###### [React best practices and patterns to reduce code - Part 2](https://dev.to/devsmitra/react-best-practices-and-patterns-to-reduce-code-part-2-54f3)

let's look at some more best practices and patterns to reduce code.

---

##### Store Tokens to an HTTP Cookie rather than localStorage

###### Bad code:

```javascript
const token = localStorage.getItem("token");
if (token) {
  axios.defaults.headers.common["Authorization"] = token;
}
```

###### Good code:

```javascript
import Cookies from "js-cookie"; //  use another library if you want

const token = Cookies.get("token");
if (token) {
  axios.defaults.headers.common["Authorization"] = token;
}
```

###### Better code:

```javascript
No Code 😉
```

**_Note:_**

- Cookies are shared with all sites on the same domain. No need to pass the token to every request. If the backend is not on the same domain as the frontend, you have to use 2nd approach.
- Use the HttpOnly attribute for to prevent access to cookie values(token) via JavaScript. but you need some flag at React app for checking route access.

---

##### Use interceptors for auth token or any other common headers

###### Bad code:

```javascript
axios.get("/api", {
  headers: {
    ts: new Date().getTime(),
  },
});
```

###### Good code:

```javascript
// only once
axios.interceptors.request.use(
  (config) => {
    // Do something before request is sent
    config.headers["ts"] = new Date().getTime();
    return config;
  },
  (error) => {
    // Do something with request error
    return Promise.reject(error);
  }
);

// Component
axios.get("/api");
```

---

##### Use context/redux for passing props to children

###### Bad code:

```javascript
const auth = { name: "John", age: 30 };
return (
  <Router>
    <Route path="/" element={<App auth={auth} />} />
    <Route path="/home" element={<Home auth={auth} />} />
  </Router>
);
```

###### Good code:

```javascript
return (
  <Provider store={store}>
    <Router>
      <Route
        path="/"
        element={<App />}
      />
      <Route
        path="/home"
        element={<Home />}
      />
    </Router>
);


// Inside child component
const { auth } = useContext(AuthContext); // For context
const { auth } = useSelector((state) => state.auth); // For redux
```

---

##### Use helper function for styled-components

###### Not bad code but difficult to read when you think in terms of px.

```javascript
const Button = styled.button`
  margin: 1.31rem 1.43rem;
  padding: 1.25rem 1.5rem;
`;
```

###### Create helper function for px to rem conversion

```javascript
const toRem = (value) => `${value / 16}rem`;
const Button = styled.button`
  margin: ${toRem(21)} ${toRem(23)};
  padding: ${toRem(20)} ${toRem(24)};
`;
```

---

##### Use common function for input data change

###### Bad code:

```javascript
const onNameChange = (e) => setName(e.target.value);
const onEmailChange = (e) => setEmail(e.target.value);

return (
  <form>
    <input type="text" name="name" onChange={onNameChange} />
    <input type="text" name="email" onChange={onEmailChange} />
  </form>
);
```

###### Good code:

```javascript
const onInputChange = (e) => {
  const { name, value } = e.target;
  setFormData((prevState) => ({
    ...prevState,
    [name]: value,
  }));
};

return (
  <form>
    <input type="text" name="name" onChange={onInputChange} />
    <input type="text" name="email" onChange={onInputChange} />
  </form>
);
```

---

##### Use intersection observer for lazy loading

###### Bad code:

```javascript
element.addEventListener("scroll", function (e) {
  // do something
});
```

###### Good code:

```javascript
const useScroll = (ele, options = {}): boolean => {
  const [isIntersecting, setIsIntersecting] = useState(false);
  useEffect(() => {
    const cb = (entry) => setIsIntersecting(() => entry.isIntersecting);
    const callback: IntersectionObserverCallback = (entries) => entries.forEach(cb);
    const observer = new IntersectionObserver(callback, options);
    if (ele) observer.observe(ele);
    return (): void => ele && observer.unobserve(ele);
  }, [ele]);
  return isIntersecting;
};


// Component
const ref = useRef<any>();
const isIntersecting = useScroll(ref?.current);

useEffect(() => {
  if (isIntersecting) {
    // call an API
  }
}, [isIntersecting]);

```

---

##### Use HOC for authentication and private route

###### Bad code:

```javascript
const Component = () => {
  if (!isAuthenticated()) {
    return <Redirect to="/login" />;
  }
  return <div></div>;
};
```

###### Good code:

```javascript
const withAuth = (Component) => {
  return (props) => {
    if (!isAuthenticated()) {
      return <Redirect to="/login" />;
    }
    return <Component {...props} />;
  };
};

// Route
<Route path="/home" component={withAuth(Home)} />;

// Component
const Component = (props) => <div></div>;
export default withAuth(Component);
```

---

##### Use Array of route object to define the routes

###### Common approach:

```javascript
return (
  <Router>
    <Route path="/" element={<App />} />
    <Route path="/about" element={<About />} />
    <Route path="/topics" element={<Topics />} />
  </Router>
);
```

###### Good code:

```javascript
const routes = [
  {
    path: "/",
    role: ["ADMIN"],
    element: React.lazy(() => import("../pages/App")),
    children: [
      {
        path: "/child",
        element: React.lazy(() => import("../pages/Child")),
      },
    ],
  },
  {
    path: "/about",
    role: [],
    element: React.lazy(() => import("../pages/About")),
  },
  {
    path: "/topics",
    role: ["User"],
    element: React.lazy(() => import("../pages/Topics")),
  },
];

const createRoute = ({ element, children, role, ...route }) => {
  const Component = role.length > 0 ? withAuth(element) : element;
  return (
    <Route key={route.path} {...route} element={<Component />}>
      {children && children.map(createRoute)}
    </Route>
  );
};

return <Routes>{routes.map(createRoute)}</Routes>;
```

**_Note:_** This requires more code, but it is more flexible. If you want to use more HOC, you have to only update createRoute.

---

##### Use Typescript

###### Nothing wrong if you don't use Typescript 😀, but it'll help you to write better code

```javascript
npx create-react-app my-app --template typescript
```

---

##### Use eslint, prettier for Formatting

```javascript
npm install -D eslint prettier
npx eslint --init
```

###### Refer this: [Eslint setup] (https://eslint.org/docs/user-guide/getting-started), [Prettier setup] (https://prettier.io/docs/en/install.html)

😥 Not added complete steps, I want to keep this short and simple. If you find any difficulties, please leave a comment.

---

##### Use pre-commit hook to run eslint and prettier

```javascript
npx mrm@2 lint-staged // This will install and configure pre-commit hook

// This script will be created at the root of your project
.husky/pre-commit

// Package.json
"lint-staged": {
  "src/**/*.{js,ts,jsx,tsx}": [
    "npm run lint",
    "npm run prettier",
    "npm run unit-test",
    "git add"
  ]
}
```

**_Note:_** 
-  You can update the config to run prettier and eslint on commit. You can add or remove the command in the project package.json.
- Better to have CI & CD setup for this, Someone can comment out the pre-commit hook and push code to git.

---

##### Use vscode extension for better development

###### [Auto Close Tag](https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-close-tag), [Auto Rename Tag](https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag), [CodeMetrics](https://marketplace.visualstudio.com/items?itemName=kisstkondoros.vscode-codemetrics), [CSS Peek](https://marketplace.visualstudio.com/items?itemName=pranaygp.vscode-css-peek), [ES7+ React/Redux/React-Native snippets](https://marketplace.visualstudio.com/items?itemName=dsznajder.es7-react-js-snippets), [Eslint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint), [GitLens](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens), [Import Cost](https://marketplace.visualstudio.com/items?itemName=wix.vscode-import-cost), [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)

**_Note:_** Must try code complexity extension(CodeMetrics). It'll help you to write better code by showing the complexity of your code.

![React best practices and patterns to reduce code - Part 3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bqgjacp5hemba1dd5vrs.png "React best practices and patterns to reduce code - Part 3")

---

Thank you for reading 😊

Got any questions or additional? please leave a comment.

### Must Read If you haven't

{% link https://dev.to/devsmitra/no-more-redux-action-creators-functions-30j %}
{% link https://dev.to/devsmitra/how-to-cancel-javascript-api-request-with-abortcontroller-36cm %}
{% link https://dev.to/devsmitra/13-typescript-utility-a-cheat-sheet-for-developer-ab3 %}
{% link https://dev.to/devsmitra/how-to-solve-rest-api-routing-problem-with-decorators-5b3n %}


### Catch me on
{% user devsmitra %}
<p>
{% cta https://www.youtube.com/@devsmitra?sub_confirmation=1 %} Youtube {% endcta %}
{% cta https://github.com/devsmitra %} Github {% endcta %}
{% cta https://www.linkedin.com/in/rahul-sharma-18b8b374 %} LinkedIn {% endcta %}
{% cta https://devsmitra.medium.com %} Medium {% endcta %}
{% cta https://stackblitz.com/@devsmitra %} Stackblitz {% endcta %} {% cta https://devsmitra.hashnode.dev %} Hashnode {% endcta %}
{% cta https://hackernoon.com/u/devsmitra %} HackerNoon {% endcta %}
</p>