3

in component A:

 const getOnClick = useCallback(
    (rec: GenericRec): (() => void) => () => {
      setSelectedRecord(rec);
    },
    [],
  );

in componant B child of A :

const openRecord = useCallback(
    (row: Row<Record>) => () => {
      getOnClick({ id: row.original.id, name: row.original.name });
    },
    [getOnClick],
  );

getOnClick is not called

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
Kaoutar BELLA
  • 61
  • 1
  • 7
  • 1
    *"Is it possible to call useCallback inside another callback"* Not unless that other callback is a hook or component. But that's okay, you're not using `useCallback` in a callback. – T.J. Crowder Aug 26 '20 at 11:14
  • It's fine to call the function you memoize with `useCallback` from another function. Please update your question with a [mcve] demonstrating the problem, ideally a **runnable** one using Stack Snippets (the `[<>]` toolbar button). Stack Snippets support React, including JSX; [here's how to do one](http://meta.stackoverflow.com/questions/338537/). (You'll have to comment out the TypeScript type annotations.) – T.J. Crowder Aug 26 '20 at 11:15

1 Answers1

2

You have an extra layer of functions in both of your useCallback calls. Unlike useMemo, useCallback directly accepts the callback that it should memoize, not a function that builds the callback.

So:

const getOnClick = useCallback(
    (rec: GenericRec): (() => void) => {
//                                     ^−−−− no () => here
        console.log("getOnClick");
        setSelectedRecord(rec);
    },
    [],
);

const openRecord = useCallback(
    (row: Row<Record>) =>
//                       ^−−−− no () => here
        getOnClick({ id: row.original.id, name: row.original.name })
    ,
    [getOnClick],
);

Live Example (with TypeScript type annotations commented out):

const { useState, useCallback } = React;

function Example() {
    const [selectedRecord, setSelectedRecord] = useState(null);
    const getOnClick = useCallback(
        (rec/*: GenericRec*/)/*: (() => void)*/ => {
            console.log("getOnClick");
            setSelectedRecord(rec);
        },
        []/*,*/
    );

    const openRecord = useCallback(
        (row/*: Row<Record>*/) =>
    //                         ^−−−− no () => here
            getOnClick({ id: row.original.id, name: row.original.name })
        ,
        [getOnClick]/*,*/
    );

    const addRecord =() => {
        console.log("addRecord");
        openRecord({
            original: {
                id: 1,
                name: "The record"
            }
        });
    };

    return (
        <div>
            <input type="button" value="Click Me" onClick={addRecord} disabled={!!selectedRecord} />
            {selectedRecord && <span>Selected record: "{selectedRecord.name}" ({selectedRecord.id})</span>}
            {!selectedRecord && <em>No record selected</em>}
        </div>
    );
}

ReactDOM.render(<Example/>, document.getElementById("root"));
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • thank you for your reply , but still the same , getOnClick is not called – Kaoutar BELLA Aug 26 '20 at 11:49
  • 1
    @KaoutarBELLA - Yes, it is -- see the **live example**. If `openRecord` is called, `getOnClick` is called. – T.J. Crowder Aug 26 '20 at 11:52
  • true , my callback was returning a function ... thanks @T.J – Kaoutar BELLA Aug 26 '20 at 12:34
  • @KaoutarBELLA - Then you'd have to call the result of `openRecord`. As I said on the question, please update your question with a [mcve] demonstrating the problem, ideally a **runnable** one using Stack Snippets (the `[<>]` toolbar button). Stack Snippets support React, including JSX; [here's how to do one](http://meta.stackoverflow.com/questions/338537/). – T.J. Crowder Aug 26 '20 at 12:44