現實場景需求
UE4像素流推送前端插件存在一個bug, 就是無法在視頻流上進行漢字的輸入, 因為該插件本質是一個<video>
標簽, 當然不能在其中使用輸入法來鍵入中文, 但是在現實數字孿生開發環境中我們肯定需要進行漢字的輸入來進行查詢和修改, 那么我們如何來實現這個功能呢?
目前我想到了三種解決方案, 第一種是在UE4程序內集成輸入法, 第二種是吧UWG放到前端頁面來做, 第三種則是在進行中文輸入插入光標時傳遞信息給UE4像素流前端, 前端因此彈出一個輸入框, 輸入完成后傳送回UE4, 更新輸入框.
目前來說第一種和第二種對我這種沒有UE4基礎和UI切圖的人來說是不切實際的, 但是第三種還是可以實現的, 但是在我用函數式組件解決的過程中, 發現了一個BUG, 即React函數式組件使用props傳參作為state時子組件useState只能獲取到第一次的傳遞的值, 以后的值也不會更新state.
遇到的問題
通俗的說, 我想實現如下的效果, 我父組件想要傳遞一個是否顯示輸入對話框的boolean狀態值, 初始值為false
, 當父組件收到要開始輸入消息時, 將改值更新為true
, 子組件收到后彈出輸入對話框, 然后輸入文字內容, 發送給UE4.
我們現在用一個父組件button點擊事件來模擬一下收到信息后發送給子組件的過程
父組件HandSendMsg核心代碼:
import React, { useState } from 'react'
import InputModal from '../../components/InputModal';
export default function HandSendMsg() {
const [inputModalVisible, setInputModalVisible] = useState(false)
return (
<div>
<InputModal
emitMessageToUE4={emitMessageToUE4}
textContent={textContent}
inputModalVisible={inputModalVisible}
/>
<button
onClick={() => {
setTextContent("lalala")
setInputModalVisible(true)
}}
style={{
position: 'absolute',
zIndex: 100,
right: 0
}}
>test</button>
</div>
)
}
子組件InputModal核心代碼:
import React, { useState } from 'react'
import { Input, Modal } from 'antd'
const { TextArea } = Input
export default function InputModal(props) {
const [inputModalVisible, setInputModalVisible] = useState(props.inputModalVisible)
const handleOk = () => {
// 發送消息給ue4, 代碼省略
setInputModalVisible(false);
};
const handleCancel = () => {
// 取消發送消息
setInputModalVisible(false);
};
return (
<>
<Modal
centered
closable={false}
destroyOnClose
title={null}
visible={inputModalVisible}
onOk={handleOk}
onCancel={handleCancel}
cancelText="取消"
okText="確定"
>
<TextArea
showCount
maxLength={100}
placeholder="請輸入內容"
allowClear
defaultValue={props.textContent}
/>
</Modal>
</>
)
}
如果是這樣, 我們會發現在傳遞給子組件InputModal中的stateinputModalVisible
不會隨着父組件的值改變而改變, 其值永遠為false, 當我們點擊父組件的button時, 並不會在子組件彈出modal對話框, 這是因為useState的原因而引起的, 后續props傳參的改變不能引起useState鈎子進行更新為true, 導致無法彈出對話框, 那么應該如何解決呢?
解決辦法
使用redux來共同管理狀態顯然是可以解決的, redux中store\ reducers 和 actions代碼再給出, 非常簡單, 其維護了這個狀態值, 給出父子組件代碼:
父組件HandSendMsg核心代碼:
import React, { useState } from 'react'
import InputModal from '../../components/InputModal';
// 引入useDispath用於分發數據
import { useDispatch } from "react-redux"
// 引入action
import { change_input_modal_visible } from "../../redux/actions/visible"
export default function HandSendMsg() {
const dispatch = useDispatch()
return (
<div>
<InputModal
emitMessageToUE4={emitMessageToUE4}
textContent={textContent}
/>
<button
onClick={() => {
setTextContent("lalala")
dispatch(change_input_modal_visible(true))
}}
style={{
position: 'absolute',
zIndex: 100,
right: 0
}}
>test</button>
</div>
)
}
子組件InputModal核心代碼:
import React, {createRef} from 'react'
import { Input, Modal } from 'antd'
// 引入useSelector用於讀取redux store中保存的數據, 引入useDispath用於分發數據
import { useSelector, useDispatch } from "react-redux"
// 引入action
import { change_input_modal_visible } from "../../redux/actions/visible"
const { TextArea } = Input
export default function InputModal(props) {
const dispatch = useDispatch()
// store里保存的數據
const inputModalVisible = useSelector(state => state.visible.inputModalVisible)
const handleOk = () => {
// 發送消息給ue4, 具體發送邏輯代碼不再展示
dispatch(change_input_modal_visible(false));
};
const handleCancel = () => {
// 取消發送消息
dispatch(change_input_modal_visible(false));
};
return (
<>
<Modal
centered
closable={false}
destroyOnClose
title={null}
visible={inputModalVisible}
onOk={handleOk}
onCancel={handleCancel}
cancelText="取消"
okText="確定"
>
<TextArea
showCount
maxLength={100}
placeholder="請輸入內容"
allowClear
defaultValue={props.textContent}
/>
</Modal>
</>
)
}