1

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?

5
  • What is data in the constructor? Commented Jan 6, 2023 at 22:00
  • Works fine when I remove this.data = data codesandbox.io/s/kind-julien-yzkgwj?file=/src/App.tsx Commented Jan 6, 2023 at 22:01
  • 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. Commented Jan 6, 2023 at 23:30
  • ah this is a simplified version of the class I'm working with and the data data field was accidentally left in after I pasted it over Commented Jan 7, 2023 at 1:51
  • @Konrad the problem is replicated when Daemon is in a separate .ts file, it appears if Daemon is in the same file as the TimeFeedback it'll work just fine! Commented Jan 7, 2023 at 1:58

1 Answer 1

2

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

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.