DEV Community

David Arce
David Arce

Posted on

Best Way to Trigger Child Component Function?

Parent Component:
Component for a page which includes a table and some forms, such as creating a new row in the table from a form and deleting a row in the table.

Table Component:
I currently have a child component that's a for a table where the params include a function for requesting data. Whenever pagination occurs, we request the next paginated data.

Actions that Should Request Data:

  • Pagination Changes on Table
  • Creating New Row in Table from Form in Parent
  • Deleting Row in Table from Parent

The Issue:
Since some actions occur in the parent or in other child components of the parent, I am unsure what the best way to call the Table Component's function. Right now I am thinking of just setting a boolean in the Parent Component that gets passed to the Table Component which calls the request data function.

Top comments (6)

Collapse
 
peerreynders profile image
peerreynders • Edited

I am unsure what the best way to call the Table Component's function.

Passing a function from the owner to the nested component is standard practice - what if that function was a subscription function?

function makePublish() {
  const listeners = new Set();

  return {
    send(payload) {
      for (const listener of listeners) listener(payload);
    },
    subscribe(listener) {
      listeners.add(listener);
      return () => listeners.delete(listener);
    }
  };
}
Enter fullscreen mode Exit fullscreen mode

Then

function Button({ send, text }) {
  return <button onClick={() => send({ color: text })}>{text}</button>;
}

function Counter({ subscribe }) {
  const { color, count, token } = useRedBlue(subscribe);
  return (
    <div class={`counter ${token}`}>
      {color}: {count}
    </div>
  );
}

function App() {
  const { send, subscribe } = useMemo(makePublish, []);
  return (
    <Fragment>
      <Button send={send} text={NAME_RED} />
      <Button send={send} text={NAME_BLUE} />
      <Counter subscribe={subscribe} />
    </Fragment>
  );
}
Enter fullscreen mode Exit fullscreen mode

So the owner creates the send(), subscribe() pair and passes subscribe to the nested component to be triggered, while send is passed to the components that do the triggering.

So now the subscribe sibling component can initiate whatever processing is requested by a send sibling component (without having to lift state up into the owner component).

function useRedBlue(subscribe) {
  const [state, dispatch] = useReducer(reducer, {
    current: NAME_RED,
    red: 0,
    blue: 0
  });
  const color = state.current;
  const [count, token] =
    color === NAME_RED
      ? [state.red, 'counter--red']
      : [state.blue, 'counter--blue'];

  useEffect(() => {
    return subscribe(dispatch);
  }, [subscribe, dispatch]);

  return {
    color,
    token,
    count
  };
}
Enter fullscreen mode Exit fullscreen mode

codesandbox

Collapse
 
izio38 profile image
izio38

Hey !
What about defining a callback in the parent (if you're using hooks) that get passed in the child (pagination) as : onNextPageRequested(). That child would call this function when user clicked on next Burton ?

If you are using a global state manager, it could be done differently

Collapse
 
allidoisace profile image
David Arce • Edited

@izio38 Hey!

I am using hooks and I do actually have a callback that's passed to the child (pagination). The child has its own function (let's say function X) that's called on its internal state change that invokes the callback from the parent. The problem lies with other components that need function X to be called. Basically a universal trigger that will invoke function X in the child (pagination).

Does it make sense to use a React Context to determine when function X needs to be invoked from many different components?

Collapse
 
izio38 profile image
izio38

I think in this partocular context where an action would be called by multiple sub-children, it's ok to introduce a context at a top level where whildren would consume and inform they need a refresh and a next / previous page.
It even could be a generic context only containing a pageNumber data and a refresh function?

What do you think?

Thread Thread
 
allidoisace profile image
David Arce

Yeah I am thinking context would be the best route here.

Collapse
 
devdufutur profile image
Rudy Nappée

Have you tried that ?
fr.reactjs.org/docs/hooks-referenc...

You can define functions which can be called via refs to your child components.