-
-
Notifications
You must be signed in to change notification settings - Fork 328
Interact with component from outside #531
-
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.
Beta Was this translation helpful? Give feedback.
All reactions
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
-
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:
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
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.
Beta Was this translation helpful? Give feedback.
All reactions
-
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.
Beta Was this translation helpful? Give feedback.
All reactions
-
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)
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
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)
Beta Was this translation helpful? Give feedback.
All reactions
-
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?
Beta Was this translation helpful? Give feedback.
All reactions
-
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.
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1