reactjs - 上下文中的 useState 挂钩重置未聚焦的输入框
问题描述
我的项目采用了一个显示名称,我希望将其保存在上下文中以供将来的组件使用以及发布到数据库时使用。所以,我有一个在上下文中设置名称的 onChange 函数,但是当它设置名称时,它会从输入框中消除焦点。这使得您一次只能输入一个字母的显示名称。状态正在更新,并且有一个 useEffect 将其添加到本地存储。我已经删除了该代码,它似乎不会影响这是否有效。
输入框不止一个,所以自动对焦属性不起作用。我曾尝试使用 .focus() 方法,但由于 useState 的 Set 部分不会立即发生,因此没有奏效。我尝试通过在 onChange 函数中设置值而不更改问题来使其成为受控输入。类似问题的其他答案在其代码中存在其他问题,导致其无法正常工作。
零件:
import React, { useContext } from 'react';
import { ParticipantContext } from '../../../contexts/ParticipantContext';
const Component = () => {
const { participant, SetParticipantName } = useContext(ParticipantContext);
const DisplayNameChange = (e) => {
SetParticipantName(e.target.value);
}
return (
<div className='inputBoxParent'>
<input
type="text"
placeholder="Display Name"
className='inputBox'
onChange={DisplayNameChange}
defaultValue={participant.name || ''} />
</div>
)
}
export default Component;
语境:
import React, { createContext, useState, useEffect } from 'react';
export const ParticipantContext = createContext();
const ParticipantContextProvider = (props) => {
const [participant, SetParticipant] = useState(() => {
return GetLocalData('participant',
{
name: '',
avatar: {
name: 'square',
imgURL: 'square.png'
}
});
});
const SetParticipantName = (name) => {
SetParticipant({ ...participant, name });
}
useEffect(() => {
if (participant.name) {
localStorage.setItem('participant', JSON.stringify(participant))
}
}, [participant])
return (
<ParticipantContext.Provider value={{ participant, SetParticipant, SetParticipantName }}>
{ props.children }
</ParticipantContext.Provider>
);
}
export default ParticipantContextProvider;
组件的父级:
import React from 'react'
import ParticipantContextProvider from './ParticipantContext';
import Component from '../components/Component';
const ParentOfComponent = () => {
return (
<ParticipantContextProvider>
<Component />
</ParticipantContextProvider>
);
}
export default ParentOfComponent;
这是我的第一篇文章,所以如果您需要有关该问题的其他信息,请告诉我。提前感谢您提供的任何帮助。
解决方案
What is most likely happening here is that the context change is triggering an unmount and remount of your input component.
A few ideas off the top of my head:
- Try passing props directly through the context provider:
// this
<ParticipantContext.Provider
value={{ participant, SetParticipant, SetParticipantName }}
{...props}
/>
// instead of this
<ParticipantContext.Provider
value={{ participant, SetParticipant, SetParticipantName }}
>
{ props.children }
</ParticipantContext.Provider>
I'm not sure this will make any difference—I'd have to think about it—but it's possible that the way you have it (with { props.children }
as a child of the context provider) is causing unnecessary re-renders.
If that doesn't fix it, I have a few other ideas:
Update context on blur instead of on change. This would avoid the context triggering a unmount/remount issue, but might be problematic if your field gets auto-filled by a user's browser.
Another possibility to consider would be whether you could keep it in component state until unmount, and set context via an effect cleanup:
const [name, setName] = useState('');
useEffect(() => () => SetParticipant({ ...participant, name }), [])
<input value={name} onChange={(e) => setName(e.target.value)} />
- You might also consider setting up a hook that reads/writes to storage instead of using context:
const useDisplayName = () => {
const [participant, setParticipant] = useState(JSON.parse(localStorage.getItem('participant') || {}));
const updateName = newName => localStorage.setItem('participant', {...participant, name} );
return [name, updateName];
}
Then your input component (and others) could get and set the name without context:
const [name, setName] = useDisplayName();
<input value={name} onChange={(e) => setName(e.target.value)} />
推荐阅读
- c++ - 多客户端 websocket 应用程序问题
- webpack - 带有部分的 webpack5 html 模板不适用于“npm run dev”
- firebase - 如何从我的存储库中获取数据,我无法获取我存储的数据
- python - 为什么这些位反转实现以如此不同的速度运行?
- asp.net-core - 如何在 .net6 中使用 WebApplicationFactory(没有可说的入口点)
- java - JavaFX Robot.getScreenCapture 导致场景之前没有更新
- unity3d - 如何在 Unity 中恢复丢失的场景
- python - 查找凸多边形外部垂直于其边缘的点
- c# - 如何在连接上使用代理?
- google-bigquery - 我可以有效地对 BigQuery 中的日期分区表进行 GROUP BY