Home > Back-end >  How do you pass a React callback function to a typescript object?
How do you pass a React callback function to a typescript object?

Time:01-07

I have a singleton class in Daemon.ts

export default class Daemon {
    
    private static instance : Daemon;
    callback : (tstring : string)=>void;
    t : number;

    constructor (callback: (tstring : string)=>void){
        this.data = data
        this.callback = callback;
        this.t = 0;
        window.setInterval(this.tick.bind(this), 1000)
    }

    public static getInstance(callback: (tstring : string)=>void){
        if(!Daemon.instance){ Daemon.instance = new Daemon(callback);}
        return Daemon.instance;
    }

    tick(){
        this.t = this.t   1
        this.callback(this.t.toString());
    }

}

Then in a separate file, Timefeedback.tsx, I have:

const TimeFeedback = () => {

    const [time, updateSimTime] = React.useState<string>("starting string");
    
    const updateTime = (tString : string) => {
      updateSimTime(tString);
      console.log(`update time called, val: ${tString}`)
    }

    const daemon = Daemon.getInstance(updateTime.bind(this));
  
    return (
      <div>
        {time}
      </div>
    );
  };

What I expect to happen:

  • the time state is updated on each tick() from the daemon.

What actually happens:

  • the callback function updateTime is successfully called, and the console log prints the correct values. But the setState function updateTime() What happens is I get console logs from TimeFeedback.tsx with the expected value of tString printed out. But the setState function setSimTime never gets called, so the text in the div remains "starting time". Why is this?

I have investigated, when calling print events inside of Daemon I get:

function() {
    [native code]
}

I tried to remove the .bind(this) inside TimeFeedback.tsx, but nothing changes except the print instead says:

tString => {
    setSimTime(tString);
    console.log(`update time called, val: ${tString}`);
  }

I also walked through with the debugger and updateSimTime does get called but it has no effect.

Why is that updateSimTime has no effect?

CodePudding user response:

No need to .bind in the component

updateTime.bind(this) doesn't make sense in a function component because a function component doesn't have a this like a class component does. Your updateTime function can be passed directly to the Daemon.getInstance function.

You also need to remove the this.data = data in the Daemon constructor because there is no data variable` (as pointed out by @Konrad in the comments).

As a best practice, I would recommend moving the code into a useEffect hook.

const TimeFeedback = () => {
  const [time, updateSimTime] = useState<string>("starting string");

  useEffect(() => {
    const updateTime = (tString: string) => {
      updateSimTime(tString);
      console.log(`update time called, val: ${tString}`);
    };
  
    Daemon.getInstance(updateTime);
  }, [updateSimTime]);

  return <div>{time}</div>;
};

CodeSandbox Link

  • Related