Best Approaches and Solutions for React Code Minification. Part 3

Hey! This is the third and final part of the series “Best Approaches and Solutions for Minifying React Code” by Rahul Sharma. Previous articles can be found at the links below:

Store the token in cookies instead of localStorage

Bad code:

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

Good code:

import Cookies from "js-cookie"; //  Вы можете использовать другую библиотеку

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

Best Code:

Без кода 😉

Note:

  • Cookies are distributed to all sites within the same domain. So there is no need to prescribe a token in every request. If the backend is not on the same domain as the frontend, then you need to use the solution from the next paragraph.

  • Use the HttpOnly attribute to avoid accessing cookies through JavaScript.


Use request interceptors for the authorization token or other standard headers

Bad code:

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

Good code:

axios.interceptors.request.use(
  (config) => {
    // Код, необходимый до отправки запроса
    config.headers["ts"] = new Date().getTime();
    return config;
  },
  (error) => {
    // Обработка ошибки из запроса
    return Promise.reject(error);
  }
);

// Компонент
axios.get("/api");

Use react context/redux to pass props to child elements

Bad code:

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

Good code:

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


// Внутри дочернего компонента
const { auth } = useContext(AuthContext); // При использовании контекста
const { auth } = useSelector((state) => state.auth); // При использовании redux

Use helper functions for styled-components

Not bad code, but hard to read as everyone is used to thinking in pixels

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

Create a helper function to convert pixels to rem

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

Use generic functions to change data inside input fields

Bad code:

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:

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 to implement lazy loading

Bad code:

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

Good code:

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;
};


// Компонент
const ref = useRef<any>();
const isIntersecting = useScroll(ref?.current);

useEffect(() => {
  if (isIntersecting) {
    // вызов API
  }
}, [isIntersecting]);

Use HOC for authorization and private navigation

Bad code:

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

Good code:

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

// Навигация
<Route path="/home" component={withAuth(Home)} />;

// Компонент
const Component = (props) => <div></div>;
export default withAuth(Component);

Use an array with navigation data objects when creating it

Standard Solution:

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

Good code:

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: it requires more code but becomes more customizable. For example, if you want to use more HOCs, all you need to do is update createRoute.


Use Typescript

Nothing wrong if you don’t use Typescript 😀try it will help make your code better.

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

Use eslint, prettier for formatting

npm install -D eslint prettier
npx eslint --init

Links for setup help: Eslint, Prettier


Use pre-commit hook to start eslint and prettier

Bad code:

npx mrm@2 lint-staged // Установка и конфигурация pre-commit хука

// Скрипт будет создан в корне вашего проекта
.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 also add or remove commands in package.json.

  • It’s better if the project has CI & CD set up for this. Someone can comment out the pre-commit hook and push it to git.


Several VSCode extensions for easier development

Auto Close Tag, Auto Rename Tag, CodeMetrics, CSS Peek, ES7+ React/Redux/React-Native snippets, Eslint, GitLens, import cost, Prettier

Note: try extensions for feature complexity estimation (CodeMetrics). This will help in writing better code, as you will see the complexity of executing the code.


Thanks for reading 😊

Similar Posts

Leave a Reply