React + r2wc in Blazor
react, r2wc/react-to-web-component, WebComponent, Blazor Server App - InteractiveServer, React in Blazor,
引言
在 NET8 Blazor Web App - InteractiveSever
模式執行用 react
+ r2wc
打包的 web-componnet。
相關文章
參考文件
開發環境
IDE: Visual Studio 2022
平台: NET8
骨架: Blazor Web App - InteractiveServer
前端: React.v18.2
bundler: webpack.v5.88
關鍵程式碼紀錄
前端 ReactWidgets 部份
React 元件測試通訊範例。
import React, { useState } from 'react'
import cx from "./WebSample.module.css"
//§ 機制:WebComponent 與 Blazor 通訊
//※ web-component 的 props 名稱需全小寫,否則通訊會失敗。
export default function WebSample({ dot_net_object: /* object */, foo /* string */, on_bar /* (payload) => void */ }) {
const [cnt, setCnt] = useState(1)
return (
<div className={cx.wall}>
<h5>來自外面:{foo || 'nil'}</h5>
<button className={cx.button} onClick={handleClick}>送出訊息到 Blazor 後端</button>
</div>
)
function handleClick() {
console.log('WebSample.handleClick', { dot_net_object, cnt })
setCnt(c => c + 1)
//## events up
//※ 透過 dotNetObject 送訊息回去,可以直達 Blazor 後端。
const message = `[${cnt}] 透過 dotNetObject 送訊息到 Blazor 後端。 - ${foo}`;
dot_net_object.invokeMethodAsync('JsInvokeBarEvent', message);
on_bar(message) // 自己送訊息回去只能送到前端!
}
}
使用 r2wc 把 react 元件打包轉譯成 web-component 元件。
"use strict";
import r2wc from '@r2wc/react-to-web-component'
import WebSample from './WebSample'
//#region 註冊 Web Components
///※註1:web-component 的命名需全小寫。
///※註2:因為 web-component 是純前端元件,經由 function 向上傳遞訊息只能送到前端。
customElements.define("web-sample", r2wc(WebSample, {
props: {
dot_net_object: "object", // 透過 dotNetObject 送訊息回去,可以直達 Blazor 後端。
foo: "string",
on_bar: "function", // 只作用在前端!
},
}));
Blazor Web App 部份
一般來說可以直接在 html 使用 web-component,然因 Blazor 與 html 不能直接互動,需間接操作。
@implements IDisposable
@inject IJSRuntime jsr
<div class="pa-2 my-2" style="border: solid 2px blue; border-radius: 8px">
<h3>TestWebSample</h3>
<p>測試 R2WC 通訊能力</p>
<MudTextField Label="輸入些文字" @bind-Value=foo />
<web-sample @ref=refWebSample foo=@foo />
@* ※若沒有透過 dotNetObject 通訊需求的話,直接使用 web-componnet 即可不用再包裝一層。 *@
<p>來自<code>web-sample</code>送上來的訊息, barMessage: @barMessage</p>
</div>
@code {
//## Resource
ElementReference refWebSample;
IDisposable? dotNetObject = null;
//## State
string foo = "從外面給值";
string barMessage = string.Empty;
public void Dispose()
{
dotNetObject?.Dispose();
dotNetObject = null;
}
protected override void OnInitialized()
{
dotNetObject = DotNetObjectReference.Create(this);
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
await jsr.InvokeVoidAsync("assignDotNetObject", refWebSample, dotNetObject);
//※ web-component 初始化 - 指定 dotNetObject。
// 必需間接使用 JSInterop 轉換才可 NET → JS。
}
/// <summary>
/// 當 React 元件有訊息送上來時觸發。
/// </summary>
[JSInvokable]
public async Task JsInvokeBarEvent(string message)
{
barMessage = message;
await InvokeAsync(StateHasChanged);
}
}
必需間接使用 JSInterop
轉換才可 NET → JS。
<!DOCTYPE html>
<html lang="zh-hant">
<head>
...略...
</head>
<body>
...略...
@* <!-- To register dotNetObject for web-components. --> *@
<script>
function assignDotNetObject(theWebComponent /* element */, dotNetObject /* object */) {
theWebComponent.dot_net_object = dotNetObject;
}
</script>
</body>
</html>
沒圖沒真象

(EOF)
Last updated