doctopus
doctopus

Reputation: 5657

Want to set state once on first render without causing uneccessary re-renders on further updates

I have a MarketOverview component that renders a bunch of cryptocurrency trading pair markets. On initialisation, I want it to render the BTC/USD market by default, which I'm doing via useEffect(). The problem is the defaultMarket gets called on every render. Moreover, defaultMarket depends on the tickers prop, so if I wrap it in useMemo(), then the eslint react-hooks plugin automatically populates tickers as a dependency.

Without useMemo():

const defaultMarket = tickers.find((ticker) => {
    return ticker.market_id === "BTC-USD";
  });

With useMemo():

const defaultMarket = useMemo(
    () =>
      tickers.find((ticker) => {
        return ticker.market_id === "BTC-USD";
      }),
    [tickers]
  );

Entire component:

export const MarketOverview = memo(({ tickers }: TProps) => {

  // Set default market on initialisation to BTC/USD
  const defaultMarket = tickers.find((ticker) => {
    return ticker.market_id === "BTC-USD";
  });

  const [selectedMarket, setSelectedMarket] = useState<ITicker | undefined>(
    undefined
  );

  useEffect(() => {
    setSelectedMarket(defaultMarket);
  }, [defaultMarket]);

  // Select market
  const selectMarket = (market: ITicker) => {
    history.push(`${PUBLIC_URL}/markets/${market.market_id}`);
    setSelectedMarket(market);
  };
  return (
    <div className="market-overview-container">
      <MarketSelector
        tickers={tickers}
        selectMarket={selectMarket}
        selectedMarket={selectedMarket}
      />
      {selectedMarket && <MarketStats selectedMarket={selectedMarket} />}
    </div>
  );
});

Upvotes: 1

Views: 2013

Answers (1)

Drew Reese
Drew Reese

Reputation: 203466

Why, then you'll never recompute defaultMarket if tickers ever updates.

If you really want to though, you can add an eslint disable for the line and use an empty dependency array so the hook runs once only on component mount.

const defaultMarket = useMemo(
  () =>
    tickers.find((ticker) => {
      return ticker.market_id === "BTC-USD";
    }),
  // eslint-disable-next-line react-hooks/exhaustive-deps
  []
);

Upvotes: 1

Related Questions