在 Day2 ,我們提到 Streamlit 的機制是可以在跑 Script 時更新 GUI 的:
import streamlit as st
import time
for i in range(5):
time.sleep(1)
st.text(str(i))
以之前的一口氣塞一包 JSON 給前端是無法達到的,因此,我們要使用 WebSocket 來做到這件事情。
構想的流程是這樣的:
在本來,我們新增一個 Component 就會這樣
container.Comps = append(container.Comps, newComp)
我們需要改成直接送這資訊給前端:
{
"parent_comp_id": "在哪個 component(container) 底下塞 component",
"component": {component config}
}
所以我們在建立 Components 時,要準備好一個 Callback,用來替換上面的 append list 操作
sendNotifyPack := func(parentID string, comp Component) {
// ...
websocket.JSON.Send(ws, pack)
}
使用 Go golang.org/x/net/websocket
包來處理 WebSocket 連接。
中斷部分我用 panic 做到這件事情。
sendNotifyPack := func(parentID string, comp Component) {
if stopUpdating.Load() {
panic(ErrUpdateInterrupt)
}
websocket.JSON.Send(ws, pack)
}
然後在外面把 panic recover 下來。
func (app *App) RunWithHandlingPanic(
name string, state *State, notifyFunc SendNotifyPackFunc) (err error) {
defer func() {
r := recover()
if r != nil {
err = tgutil.Errorf("%w: %v", ErrPanic, r)
}
}()
err = app.Run(name, state, notifyFunc)
return
}
要 Handle 的邏輯其實就是
更新機制: 當後端發來更新消息時,前端會根據消息中的訊息更新對應的组件,並讓 React 重新渲染頁面。
export class Node {
props: any
children: Node[]
parentID: string
constructor(props: any) {
this.props = props
this.children = []
this.parentID = ''
}
}
export class Forest {
nodes: { [id: string]: Node }
// ...
}
明天將介紹 StatefulWebsocket。