Js-重新呈现时输入失去焦点

我只是写文本输入,在 onChange事件中我调用 setState,因此反应重新呈现我的 UI。问题是文本输入总是失去焦点,所以我需要对每个字母重新调整焦点: D。

var EditorContainer = React.createClass({


componentDidMount: function () {
$(this.getDOMNode()).slimScroll({height: this.props.height, distance: '4px', size: '8px'});
},


componentDidUpdate: function () {
console.log("zde");
$(this.getDOMNode()).slimScroll({destroy: true}).slimScroll({height: 'auto', distance: '4px', size: '8px'});
},


changeSelectedComponentName: function (e) {
//this.props.editor.selectedComponent.name = $(e.target).val();
this.props.editor.forceUpdate();
},


render: function () {


var style = {
height: this.props.height + 'px'
};
return (
<div className="container" style={style}>
<div className="row">
<div className="col-xs-6">
{this.props.selected ? <h3>{this.props.selected.name}</h3> : ''}
{this.props.selected ? <input type="text" value={this.props.selected.name} onChange={this.changeSelectedComponentName} /> : ''}
</div>
<div className="col-xs-6">
<ComponentTree editor={this.props.editor} components={this.props.components}/>
</div>
</div>
</div>
);
}


});
156707 次浏览

在没有看到其余代码的情况下,这只是一个猜测。 创建 EditorContainer 时,为组件指定一个唯一键:

<EditorContainer key="editor1"/>

当重新呈现发生时,如果看到相同的键,这将告诉 React 不要重新生成视图,而是重新使用。然后重点项目应该保持重点。

我只是碰到了这个问题,来这里寻求帮助。检查你的 CSS!输入框不能有 user-select: none;,否则在 iPad 上不能工作。

核心原因是: 当 React re- 渲染时,您以前的 DOM ref 将是无效的。这意味着 response 已经改变了 DOM 树,而您 this. refs.input.focus 将不工作,因为这里的输入不再存在。

autoFocus属性应用到 input元素可以作为解决方案在只有一个输入需要集中的情况下执行。在这种情况下,key属性将是不必要的,因为它只是一个元素,而且您不必担心将 input元素分解为它自己的组件,以避免失去对主要组件重新呈现的关注。

我也有同样的行为。

我的代码中的问题是,我创建了一个嵌套的 jsx 元素数组,如下所示:

const example = [
[
<input value={'Test 1'}/>,
<div>Test 2</div>,
<div>Test 3</div>,
]
]


...


render = () => {
return <div>{ example }</div>
}

每次更新父元素时,这个嵌套 Array 中的每个元素都会重新呈现。因此输入每次都会丢失“裁判”支持

我通过将内部数组转换为一个反应组件解决了这个问题 (带有渲染函数的函数)

const example = [
<myComponentArray />
]


...


render = () => {
return <div>{ example }</div>
}

编辑:

当我构建嵌套的 React.Fragment时,也会出现同样的问题

const SomeComponent = (props) => (
<React.Fragment>
<label ... />
<input ... />
</React.Fragment>
);


const ParentComponent = (props) => (
<React.Fragment>
<SomeComponent ... />
<div />
</React.Fragment>
);

如果是反应路由器 <Route/>中的问题,使用 render支撑而不是 component

<Route path="/user" render={() => <UserPage/>} />


失去焦点是因为 component支柱每次都使用 React.createElement,而不是仅仅重新呈现更改。

详情请浏览: https://reacttraining.com/react-router/web/api/Route/component

提供的答案没有帮助我,这是我所做的,但我有一个独特的情况。

为了清理代码,我倾向于使用这种格式,直到我准备好将组件拉入另一个文件。

render(){
const MyInput = () => {
return <input onChange={(e)=>this.setState({text: e.target.value}) />
}
return(
<div>
<MyInput />
</div>
)

但是当我把代码直接放到 div 中时,它就失去了焦点。

return(
<div>
<input onChange={(e)=>this.setState({text: e.target.value}) />
</div>
)

我不知道这是为什么,这是唯一的问题,我写它的方式和我做的大多数文件,但如果有人做了类似的事情,这就是为什么它失去焦点。

我在 html 表中遇到了同样的问题,在这个表中,我在一个列中有输入文本行。在一个循环中,我读取了一个 json 对象,特别是创建了一些行,我有一个包含 inputtext 的列。

Http://reactkungfu.com/2015/09/react-js-loses-input-focus-on-typing/

我设法用下面的方法解决了这个问题

import { InputTextComponent } from './InputTextComponent';
//import my  inputTextComponent
...


var trElementList = (function (list, tableComponent) {


var trList = [],
trElement = undefined,
trElementCreator = trElementCreator,
employeeElement = undefined;






// iterating through employee list and
// creating row for each employee
for (var x = 0; x < list.length; x++) {


employeeElement = list[x];


var trNomeImpatto = React.createElement('tr', null, <td rowSpan="4"><strong>{employeeElement['NomeTipologiaImpatto'].toUpperCase()}</strong></td>);
trList.push(trNomeImpatto);


trList.push(trElementCreator(employeeElement, 0, x));
trList.push(trElementCreator(employeeElement, 1, x));
trList.push(trElementCreator(employeeElement, 2, x));


} // end of for


return trList; // returns row list


function trElementCreator(obj, field, index) {
var tdList = [],
tdElement = undefined;


//my input text
var inputTextarea = <InputTextComponent
idImpatto={obj['TipologiaImpattoId']}//index
value={obj[columns[field].nota]}//initial value of the input I read from my json data source
noteType={columns[field].nota}
impattiComposite={tableComponent.state.impattiComposite}
//updateImpactCompositeNote={tableComponent.updateImpactCompositeNote}
/>


tdElement = React.createElement('td', { style: null }, inputTextarea);
tdList.push(tdElement);




var trComponent = createClass({


render: function () {
return React.createElement('tr', null, tdList);
}
});
return React.createElement(trComponent);
} // end of trElementCreator


});
...
//my tableComponent
var tableComponent = createClass({
// initial component states will be here
// initialize values
getInitialState: function () {
return {
impattiComposite: [],
serviceId: window.sessionStorage.getItem('serviceId'),
serviceName: window.sessionStorage.getItem('serviceName'),
form_data: [],
successCreation: null,
};
},


//read a json data soure of the web api url
componentDidMount: function () {
this.serverRequest =
$.ajax({
url: Url,
type: 'GET',
contentType: 'application/json',
data: JSON.stringify({ id: this.state.serviceId }),
cache: false,
success: function (response) {
this.setState({ impattiComposite: response.data });
}.bind(this),


error: function (xhr, resp, text) {
// show error to console
console.error('Error', xhr, resp, text)
alert(xhr, resp, text);
}
});
},


render: function () {
...
React.createElement('table', {style:null}, React.createElement('tbody', null,trElementList(this.state.impattiComposite, this),))
...
}






//my input text
var inputTextarea = <InputTextComponent
idImpatto={obj['TipologiaImpattoId']}//index
value={obj[columns[field].nota]}//initial value of the input I read //from my json data source
noteType={columns[field].nota}
impattiComposite={tableComponent.state.impattiComposite}//impattiComposite  = my json data source


/>//end my input text


tdElement = React.createElement('td', { style: null }, inputTextarea);
tdList.push(tdElement);//add a component


//./InputTextComponent.js
import React from 'react';


export class InputTextComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
idImpatto: props.idImpatto,
value: props.value,
noteType: props.noteType,
_impattiComposite: props.impattiComposite,
};
this.updateNote = this.updateNote.bind(this);
}


//Update a inpute text with new value insert of the user


updateNote(event) {
this.setState({ value: event.target.value });//update a state of the local componet inputText
var impattiComposite = this.state._impattiComposite;
var index = this.state.idImpatto - 1;
var impatto = impattiComposite[index];
impatto[this.state.noteType] = event.target.value;
this.setState({ _impattiComposite: impattiComposite });//update of the state of the father component (tableComponet)


}


render() {
return (
<input
className="Form-input"
type='text'
value={this.state.value}
onChange={this.updateNote}>
</input>
);
}
}

我一次又一次地回到这里,并且总是在最后找到其他地方的解决办法。 因此,我将在这里记录它,因为我知道我会再次忘记这一点!

在我的案例中,input失去焦点的原因是由于我在状态更改时重新呈现了 input

虫虫代码:

import React from 'react';
import styled from 'styled-components';


class SuperAwesomeComp extends React.Component {
state = {
email: ''
};
updateEmail = e => {
e.preventDefault();
this.setState({ email: e.target.value });
};
render() {
const Container = styled.div``;
const Input = styled.input``;
return (
<Container>
<Input
type="text"
placeholder="Gimme your email!"
onChange={this.updateEmail}
value={this.state.email}
/>
</Container>
)
}
}

所以,问题在于我总是在一个地方开始编写所有代码来快速测试,然后将它们分解成单独的模块。 但是,在这里这种策略适得其反,因为更新输入更改的状态触发器呈现函数,并且焦点丢失。

修正很简单,从一开始就做模块化,换句话说,“把 Input组件从 render函数中移出来”

固定密码

import React from 'react';
import styled from 'styled-components';


const Container = styled.div``;
const Input = styled.input``;


class SuperAwesomeComp extends React.Component {
state = {
email: ''
};
updateEmail = e => {
e.preventDefault();
this.setState({ email: e.target.value });
};
render() {
return (
<Container>
<Input
type="text"
placeholder="Gimme your email!"
onChange={this.updateEmail}
value={this.state.email}
/>
</Container>
)
}
}

解决方案参考文献: https://github.com/styled-components/styled-components/issues/540#issuecomment-283664947

对我来说,这是由于在 一样组件(称为 UserList)中将搜索输入框呈现为搜索结果列表造成的。因此,每当搜索结果发生更改时,整个 UserList 组件都会重新呈现,包括输入框。

我的解决方案是创建一个完全独立于 用户列表的称为 用户列表搜索的新组件。我不需要为 UserListSearch 中的输入字段设置键就可以实现这一点。我的 UsersContainer 的呈现函数现在看起来是这样的:

class UserContainer extends React.Component {
render() {
return (
<div>
<Route
exact
path={this.props.match.url}
render={() => (
<div>
<UserListSearch
handleSearchChange={this.handleSearchChange}
searchTerm={this.state.searchTerm}
/>
<UserList
isLoading={this.state.isLoading}
users={this.props.users}
user={this.state.user}
handleNewUserClick={this.handleNewUserClick}
/>
</div>
)}
/>
</div>
)
}
}

希望这也能帮到别人。

结果我把 this绑定到了导致它重新渲染的组件上。

我觉得我应该把它贴在这里,以防其他人也有这个问题。

我必须改变

<Field
label="Post Content"
name="text"
component={this.renderField.bind(this)}
/>

<Field
label="Post Content"
name="text"
component={this.renderField}
/>

简单的修复,因为在我的情况下,我实际上不需要 thisrenderField,但希望我张贴这将有助于其他人。

我把 value螺旋桨换成了 defaultValue这样就行了。

...
// before
<input value={myVar} />


// after
<input defaultValue={myVar} />

我的回答和@z5h 说的差不多。

在我的例子中,我使用 Math.random()为组件生成唯一的 key

我认为 key只用于触发该特定组件的重新呈现,而不是重新呈现该数组中的所有组件(我在代码中返回一个组件数组)。我不知道它是用来恢复状态后,重新渲染。

移除这个对我有好处。

我的问题是,我使用项的值动态命名键,在我的例子中是“ name”,所以键是 key = { ${item.name}-${index}}。因此,当我想用 item.name 作为值更改输入时,它们的键也会发生变化,因此 response 不会识别该元素

如果输入字段位于另一个元素(例如,像 <div key={"bart"}...><input key={"lisa"}...> ... </input></div>这样的容器元素——这里的省略号表示省略的代码)中,则为 容器元素(以及输入字段)上必须有一个唯一的常量键。否则,在子级状态更新时,React 将呈现一个全新的容器元素,而不仅仅是重新呈现旧容器。逻辑上,应该只更新子元素,但是..。

我在尝试编写一个包含大量地址信息的组件时遇到了这个问题。工作代码如下所示

// import react, components
import React, { Component } from 'react'


// import various functions
import uuid from "uuid";


// import styles
import "../styles/signUp.css";


export default class Address extends Component {
constructor(props) {
super(props);
this.state = {
address1: "",
address2: "",
address1Key: uuid.v4(),
address2Key: uuid.v4(),
address1HolderKey: uuid.v4(),
address2HolderKey: uuid.v4(),
// omitting state information for additional address fields for brevity
};
this.handleChange = this.handleChange.bind(this);
}


handleChange(event) {
event.preventDefault();
this.setState({ [`${event.target.id}`]: event.target.value })
}


render() {
return (
<fieldset>
<div className="labelAndField" key={this.state.address1HolderKey} >
<label className="labelStyle" for="address1">{"Address"}</label>
<input className="inputStyle"
id="address1"
name="address1"
type="text"
label="address1"
placeholder=""
value={this.state.address1}
onChange={this.handleChange}
key={this.state.address1Key} ></input >
</div>
<div className="labelAndField" key={this.state.address2HolderKey} >
<label className="labelStyle" for="address2">{"Address (Cont.)"}</label>
<input className="inputStyle"
id="address2"
name="address2"
type="text"
label="address2"
placeholder=""
key={this.state.address2Key} ></input >
</div>
{/* omitting rest of address fields for brevity */}
</fieldset>
)
}
}

眼尖的读者会注意到,<fieldset>是一个包含元素,但它不需要键。<><React.Fragment>甚至 <div>也是如此为什么?也许只有最近的集装箱需要钥匙。我不知道。正如数学教科书所说,解释留给读者作为练习。

我解决了删除 input 和他的父元素中的 key 属性的同样问题

// Before
<input
className='invoice_table-input invoice_table-input-sm'
type='number'
key={ Math.random }
defaultValue={pageIndex + 1}
onChange={e => {
const page = e.target.value ? Number(e.target.value) - 1 : 0
gotoPage(page)
}}
/>
// After
<input
className='invoice_table-input invoice_table-input-sm'
type='number'
defaultValue={pageIndex + 1}
onChange={e => {
const page = e.target.value ? Number(e.target.value) - 1 : 0
gotoPage(page)
}}
/>

我遇到了这个问题,问题是我正在使用一个函数组件并与父组件的状态链接。如果我切换到使用类组件,问题就消失了。希望在使用功能组件时有一种方法可以解决这个问题,因为这对于简单的项目渲染器等来说更加方便。

在标签输入中包括下一个代码:

ref={(input) => {
if (input) {
input.focus();
}
}}

以前:

<input
defaultValue={email}
className="form-control"
type="email"
id="email"
name="email"
placeholder={"mail@mail.com"}
maxLength="15"
onChange={(e) => validEmail(e.target.value)}
/>

之后:

<input
ref={(input) => {
if (input) {
input.focus();
}
}}
defaultValue={email}
className="form-control"
type="email"
id="email"
name="email"
placeholder={"mail@mail.com"}
maxLength="15"
onChange={(e) => validEmail(e.target.value)}
/>

对我来说,简单的解决办法是:

<input ref={ref => ref && ref.focus()}
onFocus={(e)=>e.currentTarget.setSelectionRange(e.currentTarget.value.length, e.currentTarget.value.length)}
/>

ref触发焦点,这触发 onFocus计算结束并相应地设置游标。

我对 hook 也有同样的症状,但是我的问题是在父元素中定义一个组件。

错:

const Parent =() => {
const Child = () => <p>Child!</p>
return <Child />
}

右图:

const Child = () => <p>Child!</p>
const Parent = () => <Child />


在我的例子中,问题是我在 InputContainer 组件上设置的关键道具值和输入字段本身是使用 Math.Random ()生成的。值的非常数性质使得很难跟踪正在编辑的输入字段。

我所做的只是把 value的道具改成了 defaultValue,第二个变化是把 onChange的道具改成了 onBlur

对我来说,我在一个传送门里有一个文本区域。这个文本区域正在失去焦点。我的错误门户实现是这样的:

export const Modal = ({children, onClose}: modelProps) => {
const modalDOM = document.getElementById("modal");
const divRef = useRef(document.createElement('div'));


useEffect(()=>{
const ref = divRef.current;
modalDOM?.appendChild(ref);
return ()=>{
modalDOM?.removeChild(ref);
}
});


const close = (e: React.MouseEvent) => {
e.stopPropagation();
onClose();
};


const handleClick = (e: React.MouseEvent) => {
e.stopPropagation()
}


return (
createPortal(
<div className="modal" onClick={close}>
<div className="modal__close-modal" onClick={close}>x</div>
{children}
</div>,
divRef.current)
)
}


const Parent = ({content: string}: ParentProps) => {
const [content, setContent] = useState<string>(content);
  

const onChangeFile = (e: React.MouseEvent) => {
setContent(e.currentTarget.value);
}


return (
<Modal>
<textarea
value={content}
onChange={onChangeFile}>
</textarea>
</Modal>
)
}

结果证明下面的实现工作正常,这里我直接将模态组件附加到 DOM 元素。

export const Modal = ({children, onClose}: modelProps) => {
const modalDOM = document.getElementById("modal");


const close = (e: React.MouseEvent) => {
e.stopPropagation();
onClose();
};


return (
createPortal(
<div className="modal" onClick={close}>
<div className="modal__close-modal" onClick={close}>x</div>
{children}
</div>,
modalDOM || document.body)
)
}

在某些情况下,更改某些控件的输入中的文本可能导致父控件重新呈现(根据对道具的绑定)。 在这种情况下,焦点将丢失。编辑不应该对 DOM 中的父容器产生影响。

我有一个类似的问题,这是固定的。

const component = () => {
return <input onChange={({target})=>{
setValue(target.vlaue)
}
} />
}


const ThisComponentKeptRefreshingContainer = () => {
return(
<component />
)
}


const ThisContainerDidNot= () => {
return(
<> {component()} </>
)
}

然而,正如代码演示的那样,像元素一样调用组件子元素会产生重新呈现的效果,而像函数一样调用它则不会产生这种效果。 希望能帮到别人