Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Interact with component from outside #531

Answered by Hammer2900
Hammer2900 asked this question in Question
Discussion options

Can you tell me if it's possible to interact with the component from outside. For example, send a command to change a count variable. Here is a simple example.

import time

import idom
import ray

count, set_count = 0, 0


@idom.component
def ClickCount():
    global count, set_count
    count, set_count = idom.hooks.use_state(0)

    return idom.html.button(
        {'onClick': lambda event: set_count(count + 1)},
        [f'Click count: {count}'],
    )


@ray.remote
class ServerRun(object):
    def __init__(self):
        global count, set_count
        while True:
            count = count + 1
            time.sleep(1)


if __name__ == '__main__':
    ray.init(num_cpus=2)
    db = ServerRun.options(name='dev').remote()
    idom.run(ClickCount, port=8002)

If it could be done, then you could write real-time applications.

You must be logged in to vote

If I have understood correctly, this is the right way to interact.

import idom
from idom.server.sanic import SharedClientStateServer
from sanic import Sanic
from sanic.response import json

app = Sanic()

count, set_count = idom.Ref(), idom.Ref()


@idom.component
def ClickCountNew():
    count.current, set_count.current = idom.hooks.use_state(0)
    return idom.html.button(
        {'onClick': lambda event: set_count.current(count.current + 1)},
        [f'Click count: {count}'],
    )


@app.route('/set')
async def test(request):
    set_count.current(100)
    return json({'hello': True})


per_client_state = SharedClientStateServer(ClickCountNew, app=app)

per_client_state.run('localhost'

Replies: 1 comment · 6 replies

Comment options

I think the answer in your specific case probably depends on what exactly ray.remote does, but for the most part, the answer is yes. In fact IDOM is thead-safe. Here's a rework if your example above using threads instead of ray:

import time
from threading import Thread, Event

import idom


did_render_once = Event()
count, set_count = idom.Ref(), idom.Ref()


@idom.component
def ClickCount():
    did_render_once.set()
    count.current, set_count.current = idom.hooks.use_state(0)
    return idom.html.button(
        {"onClick": lambda event: set_count.current(count.current + 1)},
        [f"Click count: {count}"],
    )


def increment_count_every_two_seconds():
    did_render_once.wait()
    while True:
        set_count.current(count.current + 1)
        time.sleep(2)


Thread(target=increment_count_every_two_seconds, daemon=True).start()


if __name__ == "__main__":
    idom.run(ClickCount)

Which looks like this when run:

You must be logged in to vote
6 replies
@rmorshea
Comment options

Ok, it looks like using globals for cross communication is an antipattern in ray. Based on their code examples, you'll need to use an actor class instead? This probably get's fairly complicated since anything inside the ray.remote decorator could be running on an entirely separate machine. You'll have to look up how ray handles signalling and data synchronization to do this in the exact way you want.

@Hammer2900
Comment options

Thank you, great example, it should be added to the documentation, maybe someone will need it.
And the fact that it's an anti-pattern is understandable, but I required a quick example of how to interact with the component from outside.

It would also be good if you could show how to interact with the idom from fastapi. For example, we have some application on fastapi and it does some work and for example we require to send signals to the component when we do something. If it's possible =)
If idom could be embedded into asynchronous applications then it would be ideal for writing small dashboards.

@rmorshea
Comment options

I'm working on a rewrite of the documentation right now so I'll be sure to mention this: #519

As for working with existing FastAPI apps, that's relatively easy to do. Just pass in an app argument to a server implementation:

from fastapi import FastAPI
from idom import component
from idom.server.fastapi import PerClientStateServer

app = FastAPI()

@component
def MyComponent():
    ...

PerClientStateServer(MyComponent, app=app)
@Hammer2900
Comment options

If I have understood correctly, this is the right way to interact.

import idom
from idom.server.sanic import SharedClientStateServer
from sanic import Sanic
from sanic.response import json

app = Sanic()

count, set_count = idom.Ref(), idom.Ref()


@idom.component
def ClickCountNew():
    count.current, set_count.current = idom.hooks.use_state(0)
    return idom.html.button(
        {'onClick': lambda event: set_count.current(count.current + 1)},
        [f'Click count: {count}'],
    )


@app.route('/set')
async def test(request):
    set_count.current(100)
    return json({'hello': True})


per_client_state = SharedClientStateServer(ClickCountNew, app=app)

per_client_state.run('localhost', 5000)
Answer selected by Archmonger
@rmorshea
Comment options

That should do it 🚀

Although, you've imported the SharedClientStateServer which gives all users the same synchronized view. Perhaps you meant to use the PerClientStateServer?

@Hammer2900
Comment options

No this is a test case, i was checking how the state will work for everyone =) Now we can make dashboards for services very fast. Let's see how it all works in production.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
2 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.