MarkKor
MarkKor

Reputation: 91

Prevent re-render while using custom hooks

I'm experiencing something similar to this: Should Custom React Hooks Cause Re-Renders of Dependent Components?

So, I have something like this:

const ComponentA = props => {
  const returnedValue = useMyHook();
}

And I know for a fact that returnedValue is not changing (prev. returnedValue is === to the re-rendered returnedValue), but the logic inside of the useMyHook does cause internal re-renders and as a result, I get a re-render in the ComponentA as well.

I do realize that this is intentional behavior, but what are my best options here? I have full control over useMyHook and returnedValue. I tried everything as I see it, caching(with useMemo and useCallback) inside of useMyHook on returned value etc.

Update

Just to be more clear about what I'm trying to achieve:

I want to use internal useState / useEffect etc inside of useMyHook and not cause re-render in the ComponentA

Upvotes: 8

Views: 15653

Answers (5)

Vishnu Vardhan
Vishnu Vardhan

Reputation: 11

import React, { useState, useEffect } from "react";

let times = -1;
export default function useCounter(cb = () => {}) {
  useEffect(() => {
    if (times == 1) {
      console.log(times);
      cb();
    }
    times = times + 1;
  });
  return null;
}

The above snioppet could be a simple and tricky example to prevent unwanted code execution while using custom hooks, but preventing re-rendering is not possible.

Upvotes: 0

Andrew Katsewich
Andrew Katsewich

Reputation: 139

If you intend to modularize logic, options here would be to use a global state solution (context will do, you can useMemo() on returned value) or a separate component which will return null and from which you'll setState() state on upper level. A combination of them will also do of course, and I think it can be a bit cleaner then shenanigans with useRef.

Upvotes: 1

Nelson Javier Avila
Nelson Javier Avila

Reputation: 602

there is no way to avoid rerendering, each state change causes the component to be updated, to avoid rerendering I recommend that you generate an auxiliary component that receives said rerendering but this must be as a child of the component

Upvotes: -1

Sly_cardinal
Sly_cardinal

Reputation: 13043

I want to use internal useState / useEffect etc inside of useMyHook and not cause re-render in the ComponentA

If you want to avoid the renders triggered by useState() or useEffect() then they are not the right tools.

If you need to hold some mutable state without triggering renders then consider using useRef() instead.

This question has a nice comparison of the differences between useState() and useRef().

Here is a simple example:

const ComponentState = () => {
    const [value, setValue] = useState(0);
    
    return (<>
        <button onClick={() => {
            // Will trigger render
            setValue(Math.random());
        }></button>
    </>);
}
const ComponentRef = () => {
    const valueRef = useRef(0);
    
    return (<>
        <button onClick={() => {
            // Will not trigger render
            valueRef.current = Math.random();
        }></button>
    </>);
}

Upvotes: 4

Ritik Banger
Ritik Banger

Reputation: 2768

Try to find out the reason of re-rendering in your hook, probably caused due to a state update. If it is due to updation of states in useEffect then give the states and values as dependency. If your states are updating in a function, do try to call the function in order to invoke.

If these doesn't work, try to use ref. useRef hook can be used to prevent such re-renders as it will provide you with .current values.

It would be better if you remove your useEffect dependencies one by one so that you can know what dependency is causing the error and create a ref for the same.

You can share a codesandbox and I would be happy to help you out with it.

Upvotes: 2

Related Questions