Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React | props inside UseCallBack not updating inside custom hook

I've build an custom custom post hook that returns the API response and the API post. And I am using useCallback hook to set the Response state

Where it goes wrong is that the Package prop doesn't update inside the useCallback hook.

When I log Package outside the useCallback hook I get the right data inside the propertie. However when I log the Package prop inside the useCallback hook the value of Package doesn't change.

No matter how many times I press the button

I've tried creating an order state that updates everytime the Package prop updates, however whenever I set Package as an value in the scope I get an infinite loop.

I've alos added Package into the scope of the useCallback hook

example

  React.useEffect(() => {
    setOrder(Package);
  }, [Package]);

What I expect to happen is that whenever I call my custom usePostOrder hook the value of Package that is inside the useCallback is always up to date with the latest passed on prop.

CustomHook

/**
 * custom post hook that returns the API response and the API post function
 * @param {string} url
 * @param {object} Package
 * @returns {array} and @param {function}
 */

export const usePostOrder = (url, Package) => {
  const [loading, setLoading] = React.useState(true);
  const [order, setOrder] = React.useState(Package);
  const [response, setResponse] = React.useState({
    config: {
      data: []
    },
    data: {
      id: 0
    }
  });

  console.log("outside func", Package);
  const postOrder = React.useCallback(async () => {
    console.log("inside func", Package);
  }, [url, loading, Package]);

  return [response, postOrder];
};

Answer by Jake Luby with a slight adjustment

/**
 * custom post hook that returns the API response and the API post function
 * @param {string} url
 * @param {object} Package
 * @returns {array} and @param {function}
 */

export const usePostOrder = (url, Package, send) => {
  const [postOrder, setPostOrder] = React.useState();
  const [response, setResponse] = React.useState({
    config: {
      data: []
    },
    data: {
      id: 0
    }
  });

  React.useEffect(() => {
    const getData = async send => {
      //this will have the updated input Package
      await axios
        .post(ApiUrl + url, Package)
        .then(function(response) {
          setResponse(response);
        })
        .catch(function(error) {
          setResponse(error);
          console.log(error);
        });
    };

    send && getData();
  }, [send]); //this will run when url or Package changes

  return [response, postOrder];
};

useAsyncEndpoint.PropTypes = {
  url: PropTypes.url,
  user: PropTypes.object,
  club: PropTypes.object,
  cartItems: PropTypes.array
};

How I call this hook

import {usePostOrder} from "./yourHooksFolder"
  const [send, setSend] = React.useState(false);
  const [response, postOrder] = usePostOrder(
    "url",
    createOrder(user, store, cartItems),
    send
  );

  React.useEffect(() => {
    setSend(false);
  }, [response]);

// send order
  const onGoToPaymentPressed = () => {
    setSend(true);
  };



like image 221
Salman Avatar asked Nov 08 '19 20:11

Salman


People also ask

Does useCallback cause re-render?

The key takeaway here is that useCallback returns you a new version of your function only when its dependencies change, saving your child components from automatically re-rendering every time the parent renders.

Are there any problems using useCallback?

A bad use case The first problem is that useCallback() hook is called every time MyComponent renders. That reduces the render performance already. The second problem is using useCallback() increases code complexity.

Should I wrap setState in useCallback?

We must remember is that the setState function must not be passed to the useCallback dependency array. The React team suggests this: "React guarantees that setState function identity is stable and won't change on re-renders. This is why it's safe to omit from the useEffect or useCallback dependency list."

Should component update in React hooks?

shouldComponentUpdate() is used if a component's output is affected by the current change in state or props. The default behaviour is to re-render on every state change. For imitating the functionality of shouldComponentUpdate, we should pass the values in the array through which the component's output gets affected.


1 Answers

useCallback is not meant to be used like that. It doesn't actually run the function, it simply memoizes it so that between renders the same function isn't recreated.

What you want is the useEffect hook and to have the postOrder as part of the state:

export const usePostOrder = (url, Package) => {
  const [postOrder, setPostOrder] = React.useState()
  const [response, setResponse] = React.useState({
    config: {
      data: []
    },
    data: {
      id: 0
    }
  })


  React.useEffect(() => {
    const getData = async url => {
        //this will have the updated input Package
        console.log(Package) 

        //here is where you'll have your REST calls

        //set your data which will then update the return values in the hook and cause a rerender
        setPostOrder(returnValue)
        setResponse(someResponse)
    }

    getData()
  }, [url, Package]) //this will run when url or Package changes

  return [response, postOrder]
}
like image 82
Jake Luby Avatar answered Oct 21 '22 09:10

Jake Luby