上下文中的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;

这是我的第一篇文章,因此,如果您需要有关此问题的其他信息,请告诉我。预先感谢您提供的任何帮助。

解决方法

这里最有可能发生的情况是上下文更改触发了输入组件的卸载和重新安装。

一些想法浮出水面:

  1. 尝试直接通过上下文提供程序传递道具:
// this
<ParticipantContext.Provider
  value={{ participant,SetParticipant,SetParticipantName }}
  {...props}
/>

// instead of this
<ParticipantContext.Provider
  value={{ participant,SetParticipantName }}
>
  { props.children }
</ParticipantContext.Provider>

我不确定这会带来什么变化-我必须考虑一下-但是您使用它的方式(使用{ props.children }作为上下文提供者的子代)可能会导致不必要的情况重新渲染。

如果不能解决问题,我还有其他想法:

  1. 在模糊而不是更改时更新上下文。这样可以避免上下文触发卸载/重新安装问题,但是如果您的字段被用户的浏览器自动填充,则可能会出现问题。

  2. 要考虑的另一种可能性是,是否可以将其保持在组件状态直到卸载,并通过效果清理设置上下文:

const [name,setName] = useState('');
useEffect(() => () => SetParticipant({ ...participant,name }),[])
<input value={name} onChange={(e) => setName(e.target.value)} />
  1. 您还可以考虑设置一个对存储进行读写操作的钩子,而不是使用上下文:
const useDisplayName = () => {
  const [participant,setParticipant] = useState(JSON.parse(localStorage.getItem('participant') || {}));
  const updateName = newName => localStorage.setItem('participant',{...participant,name} );
  return [name,updateName];
}

然后,您的输入组件(和其他组件)可以在没有上下文的情况下获取并设置名称:

const [name,setName] = useDisplayName();
<input value={name} onChange={(e) => setName(e.target.value)} />