DEV Community

Dylan
Dylan

Posted on • Edited on

A neat way to add Redux computed value by custom hook

Someone who starts react project usually have to decide a global state library redux or mobx.
redux has a more stars in github than mobx but mobx has a unique point with @computed. It is an easy way to get computed value with javascript decorator pattern. Of course, redux can do the same thing by using reselect library.

As react implement 'hook', developers can make easily the computed value.

Assume you have fruitStore keeping price and discount data fetched by your server.

const initialState: FruitStore = {
  apple: { discount: 0.03, price: 1000 },
  orange: { discount: 0.12, price: 3000 },
  grape: { discount: 0.2, price: 8000 },
  ...
};

This data will be displayed in 3 ways at Tag Component.

  1. discounted price
  2. final billing price to the payment
  3. readable discount value with '%'

for this, you have to calculate as below

const discountedPrice: number = price * discount;
const billingPrice: number = price * (1 - discount);
const discountPercent: string = `${discount * 100} %`;

If have multiple components using these values, you have ctrl + c, ctrl + v. It makes it harder to read and re-write code.
You may think the store keeps these all data in redux. But it may force the nested object structure and become more complex as view component incremented.

Then let's write simple and efficient code with useMemo and custom hook.

// custom hook
function useFruitTag(fruit: string) {
  const { discount, price } = useSelect(({ fruitStore }) => fruitStore[fruit]);

  const discountedPrice = useMemo(() => price * discount, [discount, price]);
  const billingPrice = useMemo(() => price * (1 - discount), [discount, price]);
  const discountPercent = useMemo(() => `${discount * 100} %`, [discount]);

  return {
    discountedPrice,
    billingPrice,
    discountPercent,
  };
}

// component
function AppleTag() {
  const { discountedPrice, billingPrice, discountPercent } = useFruitTag('apple');

  return (
    <div>
      <h1>Apple</h1>
      <p>{discountedPrice}</p>
      <p>{billingPrice}</p>
      <p>{discountPercent}</p>
    </div>
  );
}

This way makes computed value without another library reselect or mobx. By using useMemo, you can use cached value and maintain easily code even if view and fruits incremented. And also, the most important thing I think is that you can distinguish various logic as you want.

p.s
This article means not that useMemo can replace reselect or what. You can read more details from here

Top comments (0)