DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Rahul Sharma
Rahul Sharma

Posted on • Updated on

React best practices and patterns to reduce code

Image description

I have been working with React.js from the past couple of years and have been using it for several different projects. While working on different projects I’ve found some common patterns I would like to share in this blog post. Without further ado, Let’s get started.

1. Create custom hooks for redux actions and dispatches

I’m not a fan of using redux, but I’ve been using it for several different projects. I’ve found that redux-thunk is used in almost all the projects I’ve worked on. I found that is more of a boilerplate code.

I've created another article about state management 3 steps to create custom state management library

const useUser = () => {
  const dispatch = useDispatch();
  const state = useSelector(); // get auth info or something

  const fetchUser = (id) => {
      return fetch(`/api/user/${id}`).then((res) => res.json())
       .then((user) => dispatch({type: "FETCH_USER",payload:user}));
    };

  const fetchUsers = () => {
      return fetch('/api/users').then((res) => res.json())
      .then((user) => dispatch({type:"FETCH_USERS",payload: user}));
    };
  return { fetchUser, fetchUsers };
}
Enter fullscreen mode Exit fullscreen mode

Inside Component

const { fetchUser } = useUser();
useEffect(() => fetchUser(1), [])
Enter fullscreen mode Exit fullscreen mode

NOTE: As you can see here I don’t have to create multiple functions for all redux actions. We can also use the useSelector hook to get any info from redux.

2. Use object instead of switch inside the reducer

This is not a good idea if you have a lot of cases to handle. You can use an object literal as an alternative to switch statements. The object literal is more readable and easier to maintain.

const actionMap = {
  INCREMENT:(state, act) => ({...state, count: state.count + 1 }),
  DECREMENT: (state, act) => ({...state, count: state.count - 1 }),
}

const reducer = (state, action) => {
  const handler = actionMap[action.type];
  return handler ? handler(state, action) : state;
};
Enter fullscreen mode Exit fullscreen mode

NOTE: The map variable must be declared outside the dispatch context otherwise it will always be re-evaluated.
A switch can be implemented using a tree which makes it O(log n) in the map(object) searching is O(1).

3. Create a hook for REST calls

you can use the browser fetch API and create your hook and avoid some repetition of code. like get data from API update in state and render.

const useFetch = (input, { auto, ...init }) => {
  const [result, setResult] = useState([null, null, true]);

  const fetcher = useCallback(
    (query, config) =>
      fetch(query, config)
        .then((res) => res.json())
        .then((data) => setResult([null, data, false]))
        .catch((err) => setResult([err, null, false])),
    [input, init]
  );

  useEffect(() => {
    if (auto) fetcher(input, init);
  }, []); // if you want to fetch data only once, do this.

  return [...result, fetcher];
  //fetcher(refetch) function or can be used for post api call
};

Enter fullscreen mode Exit fullscreen mode

Inside Component

const Users = () => {
  const [err, users, loading, refetch] = useFetch(`/api/users`, {auto:true});

  const onClick = () => refetch(...);

  return (
    <div>
      {users.map((user) => <User key={user.id} user={user} />)}
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

NOTE: It’s similar to react-query/useSWR, both the libraries have much more to offer. you can use these libraries, but if you have restrictions on your project you can go ahead with this approach avoid some extra code.

4. Code Splitting

use React.lazy, It is a very powerful tool that allows you to load components only when they are needed. The React.lazy function lets you render a dynamic import as a regular component.

A good place to start is with routes. When you go with the traditional approach, you have to load both components before rendering them, but this is not a good approach, because it will take extra time to load all components. Even though we are not showing the component.

We can use react.lazy to load the components asynchronously. So when you are at the first(Home) page, you can load the first component and when you are at the second(About) page, you can load the second component. This way we can avoid unnecessary loading of components.

const Home = React.lazy(() => import('./Home'));
const About = React.lazy(() => import('./About'));
function MyComponent() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <Route path="/home" component={Home} />
      <Route path="/about" component={About} />
    </Suspense>
  );
}
Enter fullscreen mode Exit fullscreen mode

NOTE: This is a very simple use case but what if we have 100’s of routes and components. You will see a huge difference in the performance.

Reference:
Code-Splitting β€” React (reactjs.org)

Thank you for reading 😊

Got any questions or additional? please leave a comment.


Must Read If you haven't
No more redux action creator functions
How to cancel Javascript API request with AbortController
13 Typescript Utility: A Cheat Sheet for Developer
How to solve Express.js REST API routing problem with decorators?
3 steps to create custom state management library with React Hooks and Context API

More content at Dev.to.
Catch me on Github, Twitter, LinkedIn, Medium, and Stackblitz.

Top comments (7)

Collapse
 
katsenkatorz profile image
Jeff • Edited on

Hello thx to this post, you have an error on example 3.

replace setUsers by setResult

Collapse
 
devsmitra profile image
Rahul Sharma Author • Edited on

Sorry my bad, Thanks for pointing it out.

Collapse
 
amn3s1a2018 profile image
Amn3s1a2018

Also in example 3...
The useCallback second parameter shouldn't be an empty array instead?
I don't see why would we need a new function instance for every new input / init combination.

Collapse
 
rain84 profile image
rain84
  1. Create a hook for REST calls

refetch - cb will not trigger loading-state, please check you code

Also it would be nice to use async-await syntax. It is already 2022 )

Collapse
 
fires3as0n profile image
fires3as0n

If this are the best practices, idk what are the worst

Collapse
 
ryannerd profile image
Ryan Jentzsch

I detest Redux. Always use ReactN when I can -- so much easier, lightweight with the same functionality as Redux plus some.

Collapse
 
ramizqazi profile image
Rameez Qazi

nice

🌚 Friends don't let friends browse without dark mode.

Sorry, it's true.