ipyreact icon indicating copy to clipboard operation
ipyreact copied to clipboard

Investigating JavaScript prime number widget implementation.

Open kolibril13 opened this issue 2 years ago • 3 comments

kolibril13 avatar Apr 28 '23 11:04 kolibril13

This is not a real pr, the purpose is more for talking about the ipyreact pattern. The Situation: I have a widget that contains a button. When the button is clicked, the value count increases. A message is shown that notifies if the number of total clicks is a prime number or not.

In the first widget, I use a prime_message traitlet to communicate with the user. When the button is pressed, a new message is calculated and displayed correctly. The message can also be manipulated by primepy.prime_message = "Hello World"

Now I want to do the same thing, but make the calculations in JavaScript. That also works, but I don't know how to allow the user to manipulate the message by e.g. primejs.prime_message = "Hello World".

@paddymul : would you be interested in investigating how the

prime_message = isPrimeNumber(count);
return <span> {prime_message} </span>;

pattern can be used in a way that prime_message = isPrimeNumber(count); only gets called on number change?

kolibril13 avatar Apr 28 '23 12:04 kolibril13

I think you want to use the setter for primeMessage, not set it directly.

So

export const MyUpdater = ({ count, prime_message}) => {
    prime_message = isPrimeNumber(count); //This feels very un-reactlike because you are modifying a property inplace
    return <span> {prime_message} </span>;
    };

Should be something like

export const MyUpdater = ({ count, prime_message}) => {
    return <span> {prime_message} </span>;
    };

 export default function ({ on_count, count, prime_message, on_prime_message}) {
    on_prime_message(isPrimeNumber(count));
    return (
        <div>
        <button onClick={() => on_count(count + 1)}>{count} times clicked</button>
        <br />
        <MyUpdater count={count} prime_message = {prime_message}/>
        </div>
    );
    }
    """

I don't think the above will work though, because it will result in a loop.

I'm not sure I have a good answer.

paddymul avatar Apr 28 '23 13:04 paddymul

Thanks for your suggestion. I just included your suggestions, it did not result in a loop, however the line on_prime_message(isPrimeNumber(count)); does not allow setting the message by primejs.prime_message = "Hello World":

import ipyreact
from traitlets import  Any , Int

class PrimeJavaScriptWidget(ipyreact.ReactWidget):
    prime_message = Any("Click the Button").tag(sync=True)    # <- TODO: this message does not show up because prime_message is overwritten
    count = Int(0).tag(sync=True)

    _esm = """
    import * as React from "react";

    function isPrimeNumber(n) {
    for (let i = 2; i < n; i++) {
        if (n % i === 0) {
        return "No 🌐🧊🧊🧊";
        }
    }
    return "Yes 🌐✅✅✅";
    }

    export const MyUpdater = ({ count, prime_message}) => {
        return <span> {prime_message} </span>;
        };


    export default function ({ on_count, count, prime_message, on_prime_message}) {
    on_prime_message(isPrimeNumber(count));
    return (
        <div>
        <button onClick={() => on_count(count + 1)}>{count} times clicked</button>
        <br />
        <MyUpdater count={count} prime_message = {prime_message}/>
        </div>
    );
    }

    """
primejs = PrimeJavaScriptWidget()
primejs.prime_message = "Hello World"  # <- TODO
primejs

kolibril13 avatar Apr 28 '23 13:04 kolibril13