skip to Main Content

I have a general concept, and I would like to know if it is a good approach and if it will work. Let’s assume I have two hooks. Hook #1 is useClient, which has a state called range. I expose this state to a UI component and allow the UI to set its state. I also have another hook, Hook #2, called useOrders, where I import the range state from the useClient hook. I then use the useEffect hook to detect any changes in the range state and, if there is a change, fetch data.

My question is: If the range state changes in the useClient hook, will the useEffect in the useOrders hook run? How is this state propagation and effect triggering achieved in React hooks?

Any insights or suggestions on this approach would be highly appreciated.

Here are the examples of my hooks:

UseClient Example:

const useClient = () => {
  const { id } = useParams();
  const [range, setRange] = useState({
    from: new Date().toISOString(),
    to: new Date().toISOString(),
  });

  return {
    range,
    setRange,
  };
};

export default useClient;

UseOrders Example:

import useClient from './useClient';

const useOrders = () => {
  const { range } = useClient();
  const { id } = useParams();
  const [orders, setOrders] = useState([]);
  const [pagination, setPagination] = useState({
    page: 1,
    limit: 10,
    total: 0,
    totalPages: 1,
  });

  const fetchOrders = useCallback(async () => {
    const params = {
      page: pagination.page,
      limit: pagination.limit,
      from: range.from,
      to: range.to,
    };

    try {
      const response = await api.get(`order/getOrders/${id}`, { params });
      if (response.data.success) {
        setOrders(response.data.orders);
        setPagination((prev) => ({
          ...prev,
          total: response.data.pagination.total,
          totalPages: response.data.pagination.totalPages,
        }));
      }
    } catch (error) {
      console.error('Fetching Orders error:', error);
    }
  }, [id, pagination.page, pagination.limit, range]);

  useEffect(() => {
    fetchOrders();
  }, [fetchOrders, range, pagination.page, pagination.limit]);

  return {
    orders,
    pagination,
    setPagination,
  };
};

export default useOrders;

2

Answers


  1. Chosen as BEST ANSWER

    as @Matt Morgan mentioned, context provider is the solution for this

    const ClientContext = createContext();
    
    // Create a provider component
    export const ClientProvider = ({ children }) => {
      const [range, setRange] = useState({
        from: new Date().toISOString(),
        to: new Date().toISOString(),
      });
    
      return (
        <ClientContext.Provider value={{ range, setRange }}>
          {children}
        </ClientContext.Provider>
      );
    };
    

  2. No. You haven’t illustrated the UI component in which you set state in useClient, but based on the rest of the code, the answer is no.

    Your UI component (setting the range) will be bound to a different instance of the state within useClient— its own copy, in other words.

    I wouldn’t expect any relationship between the state of useClient you call in one component and the instance you call from a different component.

    Of course, this would be different if the state were stored in a shared ancestor, like a context provider.

    Here’s the explainer from up-to-date version of react.dev, which explains it slightly differently.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search