Categories
React Answers

How to Use the React useEffect Hook with Debounce?

Sometimes, we may not want to run the code in the useEffect hook immediately after a state update.

In this article, we’ll look at how to use the useEffect hook with the code inside the useEffect callback debounced.

Use the React useEffect Hook with Debounce

We can create our own hook that uses the useEffect hook to run code with the useEffect callback debounced.

To do this, we can write:

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

const useDebounce = (value, delay) => {
  const [debouncedValue, setDebouncedValue] = useState("");
  const firstDebounce = useRef(true);

  useEffect(() => {
    if (value && firstDebounce.current) {
      setDebouncedValue(value);
      firstDebounce.current = false;
      return;
    }

    const handler = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    return () => clearTimeout(handler);
  }, [value, delay]);

return debouncedValue;
};

export default function App() {
  const value = useDebounce("abc", 1000);

  useEffect(() => {
    console.log(value);
  }, [value]);

  return <div>{value}</div>;
}

We create the useDebounce hook with the value and delay parameters.

value is the value we want to set.

delay is the denounce delay for the useEffect callback code.

We have the firstDebounce ref to keep track of whether the denounced code is running the first time.

In the useEffect callback, we set firstDebounce.current to false so that we know that it’s not the first time that the denounced code is run it.

Then we call the setTimeout function with a callback with the denounced code.

In the callback, we call setDebouncedValue to set the debouncedValue state value.

Then we return the call that runs clearTimeout which runs when the component is unmounted.

In App , we call useDebounce with the value we want to set and the delay.

Then we log the value in the useEffect callback when the value value changes.

And we also render the value below that.

Now we should see the 'abc' string rendered and logged after 1 second.

Conclusion

We can create our own hook to run code that we want to denounce within the useEffect callback.

Categories
React

How to Update a State Inside the setInterval Callback in a React Hook?

The setInterval function lets us run code in our JavaScript apps periodically.

We may sometimes use this in React component to update a state periodically with new values.

In this article, we’ll look at how to update a state inside the setInterval callback in a React hook.

Running setInterval in a React Component

To run setInterval in a React component, we should put it in the useEffect hook.

The useEffect hook is used for committing side effects, which includes creating timers.

Therefore, we can write something like:

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

export default function App() {
  const [gamePlayTime, setGamePlayTime] = useState(0);

  useEffect(() => {
    const gameStartInternal = setInterval(() => {
      setGamePlayTime((t) => t + 1);
    }, 1000);

    return () => {
      clearInterval(gameStartInternal);
    };
  }, []);

  return <div>{gamePlayTime}</div>;
}

We have the gamePlayTime state which we update by calling setGamePlayTime .

Next, we call useEffect with a callback and create the timer inside the callback by calling setInterval .

We pass in 1000 as the 2nd argument so that the setInterval callback only runs 1000 milliseconds.

It returns a timer ID so that we can call clearInterval on it when the component unmounts.

And we did that in the callback we return in the useEffect callback.

The callback we return is run when we unmount the component.

We pass in an empty array into the 2nd argument so that the useEffect callback runs only once when the component mounts.

This way, we don’t create the timer more than once.

Then below that, we display the gamePlayTime .

Now we should see the gamePlayTime value update every second on the screen and the latest value displayed.

Conclusion

We just call setInterval in the useEffect callback to create the timer.

When we unmount the component, we call clearInterval in the callback we return to clear it when we unmount the component.

Categories
React

How to Run the React useEffect Hook Callback Only When All Dependencies Change?

Sometimes, we only want to run the useEffect hook callback when all the dependencies change.

In this article, we’ll look at how to run the React useEffect hook callback only when all the dependencies change.

React useEffect Hook Callback Only When All Dependencies Change

To run the useEffect hook callback only when all the dependencies change, we can store the previous values in a ref and then compare them to the latest values.

If the previous values are different from the previous values, then we run the useEffect callback code.

For instance, we can write:

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

export default function App() {
  const [name, setName] = useState("");
  const [age, setAge] = useState("");

  const previousValues = useRef({ name, age });

  useEffect(() => {
    if (
      previousValues.current.name !== name &&
      previousValues.current.age !== age
    ) {
      console.log(name, age);
      console.log(previousValues.current);
      previousValues.current = { name, age };
    }
  });

  return (
    <div>
      <input
        placeholder="name"
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
      <input
        placeholder="age"
        value={age}
        onChange={(e) => setAge(e.target.value)}
      />
    </div>
  );
}

We have the name and age states that we defined with the useState hook.

Then we create the previousValues ref to store the previous values of name and age in an object.

We store them in a ref so that when the value of it changes, it won’t trigger a re-rendering of the component.

This lets us get both the previous and current values since re-rendering will erase the previous state values if we don’t store them in a ref.

Then in the useEffect callback, we compare the values of the current and previous values of name and age .

And if they’re both different, then we log the values of name and age .

And then we store the previous values of the name and age in an object and assign them to previousValues.current to store them in a ref.

We don’t pass in a 2nd argument to useEffect so it runs on every render.

Below that, we have 2 inputs that we can type into to change the value of name and age .

Now when we type in different values into the inputs, we see the console log run.

Conclusion

To run code in a useEffect callback when all the dependencies change, we can store the previous values of the states in a ref.

Then we can compare them in the useEffect callback and all the previous and current values are different, then we can run the code we want to run.

Categories
React

How to Use React Context API with Multiple Values for Providers?

The React Context API is handy for letting us share data between components easily.

Sometimes, we may want to share multiple states between components.

In this article, we’ll look at how to share multiple states between components with one context provider.

Use React Context API with Multiple Values for Providers

We can pass in anything we want to the value prop of the context provider component.

So sharing multiple states with one provider is no problem.

For instance, we can write:

import React, { useContext, useState } from "react";
const CountContext = React.createContext("count");

const DescendantA = () => {
  const { count, setCount, count2, setCount2 } = useContext(CountContext);

  return (
    <>
      <button onClick={() => setCount((c) => c + 1)}>Click me {count}</button>
      <button onClick={() => setCount2((c) => c + 1)}>Click me {count2}</button>
    </>
  );
};
const DescendantB = () => {
  const { count, setCount, count2, setCount2 } = useContext(CountContext);

return (
    <>
      <button onClick={() => setCount((c) => c + 1)}>Click me {count}</button>
      <button onClick={() => setCount2((c) => c + 1)}>Click me {count2}</button>
    </>
  );
};
export default function App() {
  const [count, setCount] = useState(0);
  const [count2, setCount2] = useState(0);
  return (
    <CountContext.Provider value={{ count, setCount, count2, setCount2 }}>
      <DescendantA />
      <DescendantB />
    </CountContext.Provider>
  );
}

We create the CountContext with the React.createContext method.

Then we wrap the CountContext.Provider component around the DescendantA and DescendantB components.

We pass in the state getter and setters we defined in App all to one object into the value prop.

Then in the DescendantA and DescendantB components, we call useConext with CountContext to return the object we passed into the value prop.

We destructured all the properties and use them.

We show count and count2 in the buttons.

And we call setCount and setCount2 in the button click handlers.

Now when we click on the buttons, we see the counts go up.

Conclusion

We can pass in anything we want into the value prop of the context provider component in React.

So we can share anything between components as long as we pass them into the value prop.

Categories
React

How to Use the Axios HTTP Client in React useEffect Hook?

In many situations, we need to make HTTP requests in our code to get or submit data in our React components.

Axios is a popular HTTP client library that we can use to make HTTP requests easily.

In this article, we’ll look at how to use the Axios HTTP client with the useEffect hook to make HTTP requests.

Use the Axios HTTP Client with the React useEffect Hook

We can make HTTP requests when the component mounts by calling the useEffect hook with an empty array in the 2nd argument.

For instance, we can write:

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

export default function App() {
  const [data, setData] = useState([]);

  const getData = async () => {
    const { data } = await axios.get(`https://yesno.wtf/api`);
    setData(data);
  };

  useEffect(() => {
    getData();
  }, []);

  return <div>{JSON.stringify(data)}</div>;
}

We define the getData function to make a GET request with the axios.get method.

The function is async since axios methods return a promise.

We just pass in a URL to make a GET request.

We’ve to define the getData function outside the useEffect hook since the useEffect callback should be a synchronous function.

The empty array in the 2nd argument means that we make the request only when the component mounts.

We call setData to set the data state and we render the data in the JSX code.

If we want to make HTTP requests when a state or prop changes, then we should pass those into the array in the 2nd argument.

Using the axios-hooks Library

We can also use the axios-hooks library to let us make request with a custom hook that uses the Axios library.

To use it, we install it by writing:

npm install axios axios-hooks

Then we write:

import React from "react";
import useAxios from "axios-hooks";

export default function App() {
  const [{ data, loading, error }, refetch] = useAxios("https://yesno.wtf/api");

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error!</p>;

  return <div>{JSON.stringify(data)}</div>;
}

We call useAxios to return an array with an object that has the data , loading , and error properties.

data has the response data.

loading has the loading state. It’s true if the request is loading.

error has the error state. It’s true if the request results in an error.

We can call the refetch function to make the request again.

Conclusion

To use Axios with the useEffect hook, we just define an async function and call it inside the useEffect callback.

Alternatively, we can use the useAxios hook provided by the axios-hooks library.