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

Sign up
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
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.

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.

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)
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
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?

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

AltStyle によって変換されたページ (->オリジナル) /