skip to Main Content

In my react js application i have 2 components, in one component i have a button and in second i want to get the moment when user clicks the button. For this i created a context where i have 2 functions, one allow user using it with the button, and second one is used in another component.

Context
import React, { createContext, useContext, useRef, useMemo } from "react";

// Define context properties
const ActionsContext = createContext();

export const ActionsProvider = ({ children }) => {
  const triggerCallbackRef = useRef(null);

  // Function to register the callback
  const registerCallback = (callback) => {
    triggerCallbackRef.current = callback; // Store the callback
  };

  const value = useMemo(
    () => ({
      onGetAction: () => triggerCallbackRef.current,
      onTrigerAction: registerCallback,
    }),
    []
  );

  return (
    <ActionsContext.Provider value={value}>{children}</ActionsContext.Provider>
  );
};

// Custom hook to use the PageActions context
export const useActions = () => {
  const context = useContext(ActionsContext);
  if (!context) {
    throw new Error(" must be used within a Provider");
  }
  return context;
};


import React, { useEffect } from "react";
import { useActions } from "./context";

const MyComponent = () => {
  const { onTrigerAction } = useActions(); // Get the register function

  return <button onClick={onTrigerAction}>click</button>;
};

export default MyComponent;

import React, { useEffect } from "react";
import { useActions } from "./context";

const MyOtherComponent = () => {
  const { onGetAction } = useActions();
  onGetAction(() => {
    console.log("button is cliked");
  });
  return "Hello";
};

export default MyOtherComponent;

 <ActionsProvider>
  <MyComponent />
  <MyOtherComponent />
 </ActionsProvider>

I expect to trigger the console log here

 onGetAction(() => {
    console.log("button is cliked");
  });

but nothing happens when i click.

How to fix?

2

Answers


  1. You seem to have your object properties mixed up, your onGetAction should register your callback, and then onTrigerAction should trigger the callback stored in your ref (if it’s set). You currently have it the wrong way around and also need to change it so you’re invoking the callback stored in current with ():

    const value = useMemo(
      () => ({
        onGetAction: registerCallback,
        onTrigerAction: (...args) => triggerCallbackRef.current?.(...args),
      }),
      []
    );
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
    <script src="https://unpkg.com/@babel/[email protected]/babel.min.js"></script>
    <script type="text/babel">
    const { createContext, useCallback, useContext, useRef, useMemo, useEffect } = React;
    
    // Define context properties
    const ActionsContext = createContext();
    
    const ActionsProvider = ({ children }) => {
      const triggerCallbackRef = useRef(null);
    
      // Function to register the callback
      const registerCallback = useCallback((callback) => {
        triggerCallbackRef.current = callback; // Store the callback
      }, []);
    
      const value = useMemo(
        () => ({
          onGetAction: registerCallback,
          onTrigerAction: (...args) => triggerCallbackRef.current?.(...args),
        }),
        [triggerCallbackRef, registerCallback] // these are both stable so this is equivalent to having an empty dependency array
      );
    
      return (
        <ActionsContext.Provider value={value}>{children}</ActionsContext.Provider>
      );
    };
    
    // Custom hook to use the PageActions context
    const useActions = () => {
      const context = useContext(ActionsContext);
      if (!context) {
        throw new Error(" must be used within a Provider");
      }
      return context;
    };
    
    const MyComponent = () => {
      const { onTrigerAction } = useActions(); // Get the register function
    
      return <button onClick={onTrigerAction}>click</button>;
    };
    
    const MyOtherComponent = () => {
      const { onGetAction } = useActions();
      onGetAction(() => {
        console.log("button is cliked");
      });
      return "Hello";
    };
    
    ReactDOM.createRoot(document.body).render(<ActionsProvider>
      <MyComponent />
      <MyOtherComponent />
    </ActionsProvider>);
    </script>
    Login or Signup to reply.
  2. you have to do something like that

    in this part you creating state using context hook.

    import React, { createContext, useContext, useState, useCallback } from 'react';
    
    // Create a context
    const Context= createContext();
    
    // Create a provider component
    export const MyProvider = ({ children }) => {
        const [message, setMessage] = useState('');
    
        // Define a callback function
        const updateMessage = useCallback((msg) => {
            setMessage(msg);
            //also you can write additional logic here
        }, []);
    
        return (
            <Context.Provider value={{ message, updateMessage }}>
             <Child/>
            </Context.Provider>
        );
    };
    
    

    here you are calling the context api.
    and update the state this will trigger your callback automatically.

    import React, { useContext } from 'react';
    import { Context } from './MyProvider';
    
    const Child = () => {
        const { message, updateMessage } = useContext(Context);
    
        const handleClick = () => {
           //here you can triggert your call back
            updateMessage('Hello from Child');
        };
    
        return (
            <div>
                <p>Current Message: {message}</p>
                <button onClick={handleClick}>Update Message</button>
            </div>
        );
    };
    
    export default Child;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search