我在下面有一个图表和一个输入字段。基本上用户可以提出一个问题,图表会相应地改变。这是它的样子
这是下面的代码示例(忽略 CoreUI 语法)
<CRow>
<CCol xs="12" sm="12" lg="12">
<CCard id="answerScreen" style={{height: "500px"}}>
{
!tempResponse.loading? tempResponse.data.map(value => (
<ChartRender
key={uuidv4()}
data={value}
/>
))
:
<Loader/>
}
</CCard>
</CCol>
</CRow>
<CRow>
<CCol xs="12" sm="12" lg="12">
<CCard>
<CCardBody>
<CForm className="form-horizontal">
<CFormGroup>
<CInputGroup size="lg" className="input-prepend">
<CInputGroupPrepend>
<CInputGroupText className="">@Ask</CInputGroupText>
</CInputGroupPrepend>
<CInput
size="16"
type="text"
value={userInput || ""}
onChange={e=> handleTextBoxInput(e)}
onClick={e=> handleTextBoxClick(e)}
onKeyPress={e => handleTextBoxEnter(e)}
id="userQuery"
/>
<CInputGroupAppend>
<CButton color="primary">Send</CButton>
</CInputGroupAppend>
</CInputGroup>
</CFormGroup>
</CForm>
</CCardBody>
</CCard>
</CCol>
</CRow>
这就是我定义状态的方式
const [userInput, setUserInput] = React.useState("");
const [tempResponse, setTempResponse] = React.useState({
data: []
})
怀疑这部分代码有问题
<CInput
size="16"
type="text"
value={userInput || ""}
onChange={e=> handleTextBoxInput(e)}
onClick={e=> handleTextBoxClick(e)}
onKeyPress={e => handleTextBoxEnter(e)}
id="userQuery"
/>
我什至尝试像这样将 useCallback
添加到 onChange
函数
const handleTextBoxInput = useCallback(e =>{
e.preventDefault();
setUserInput(e.target.value)
}, [])
但是没有帮助。我什至阅读了 memo
,但不确定在我的情况下在哪里或如何应用它。我做错了什么?
观察
如 @Matthew
所述,箭头语法每次都会创建不同的回调,这有助于重新渲染,因此必须删除。
但即使在删除它之后,每次按下一个键时图表都会重新呈现。我正在使用 Chartjs
,它在内部使用 canvas
。 Chartjs
有问题吗?
答案 0 :(得分:2)
您对有问题的代码是正确的。
<CInput
size="16"
type="text"
value={userInput || ""}
onChange={e=> handleTextBoxInput(e)} // performance issue
onClick={e=> handleTextBoxClick(e)} // performance issue
onKeyPress={e => handleTextBoxEnter(e)} // performance issue
id="userQuery"
/>
当上面的代码多次运行时,每次都会重新创建函数。因此,与其这样做,以下内容就足够了
<CInput
size="16"
type="text"
value={userInput || ""}
onChange={handleTextBoxInput}
onClick={handleTextBoxClick}
onKeyPress={handleTextBoxEnter}
id="userQuery"
/>
useCallback
钩子返回一个回调函数。您可以简单地将返回值用作普通事件回调。
答案 1 :(得分:1)
在您的输入中,每次按键都会触发两个事件 - onKeyPress
和 onChange
- 删除 onKeyPress
。
我怀疑 handleTextBoxEnter
调用了更新 tempResponse 的 setTempResponse
。设置 UI 所依赖的状态将触发重新渲染。
您还应该使用 onSubmit 事件处理表单提交。如果某个元素在表单内具有焦点并且按下了 Enter 按钮 - 它将触发 onSubmit。
<form onSubmit={handleTextBoxEnter}></form>
此外,如果一个键发生变化,React 将重新渲染。您正在密钥中调用一个函数,因此它会在每次更新时更新。
tempResponse.data.map((value, i) => (
<ChartRender key={`chart-${i}`} data={value} />
))
仅供参考,手动创建 UUID 以防止过度使用密钥。
export const YourComponent = (): JSX.Element => {
const [userInput, setUserInput] = useState('');
const [tempResponse, setTempResponse] = useState({ data: [], loading: true });
useEffect(()=>{
// handle initial data loading and set loading to false
}, [])
const handleSubmit = (e) => {
e.preventDefault();
setTempResponse(your_state_data);
};
// e.preventDefault shouldn't be used here and is not required
const handleChange = ({ target }) => setUserInput(target.value);
if (tempResponse.loading) {
return <Loading />;
}
// action is set to # for iOS - an action is required to show the virtual submit button on the keyboard
return (
<>
<form action="#" onSubmit={handleSubmit}>
<input defaultValue={userInput} onChange={handleChange} type="text" />
<button type="submit">Submit</button>
</form>
{!!tempResponse.length &&
tempResponse.data.map((value, i) => (
<ChartRender key={`chart-${i}`} data={value} />
))}
</>
);
};