React.js - 在重新渲染时输入失去焦点

Kra*_*rab 76 javascript reactjs

我只是写文本输入和onChange我调用的事件setState,所以React重新呈现我的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>
        );
    }

});
Run Code Online (Sandbox Code Playgroud)

z5h*_*z5h 67

没有看到你的其余代码,这是一个猜测.创建EditorContainer时,请为组件指定唯一键:

<EditorContainer key="editor1"/>

当重新渲染发生时,如果看到相同的密钥,这将告诉React不要破坏并重新生成视图,而是重用.然后焦点项目应保持焦点.

  • 在输入中添加键没有帮助 (3认同)
  • 这解决了我渲染包含输入表单的子组件的问题。但是在我的情况下,我需要相反的选择–表单并没有在需要时重新呈现。添加key属性有效。 (2认同)
  • 也许包含您输入内容的组件也已重新渲染。检查封闭组件上的钥匙。 (2认同)
  • 感谢你的回答!此类问题通常是由于密钥造成的。我有同样的问题。而且,我不小心不小心把它放在了 General key={Math.random()} 中 (2认同)

spe*_*.sm 30

如果它是反应路由器中的问题,请<Route/>使用renderprop而不是component.

<Route path="/user" render={() => <UserPage/>} />
Run Code Online (Sandbox Code Playgroud)


失去焦点是因为component道具React.createElement每次使用而不是仅仅重新渲染变化.

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

  • 你救了我的命——就这么简单! (3认同)
  • 这基本上是我的问题.具体来说,我将一个匿名函数传递给组件prop,触发焦点丢失:`<Route component = {()=> <MyComponent />} />`,当我应该完成`<Route component = {MyComponent } />` (2认同)

Dee*_*pak 26

我一次又一次地回到这里,总是在最后找到解决方案.所以,我会在这里记录,因为我知道我会再次忘记这一点!

原因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>
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

所以,问题是我总是开始在一个地方编码所有内容以快速测试,然后将其全部分解为单独的模块.但是,这里的策略适得其反,因为在输入更改时更新状态会触发渲染功能,并且焦点会丢失.

修复很简单,从一开始就进行模块化,换句话说,"将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>
    )
  }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 这个故事的主旨是,对于 React 类组件,不要在 render 函数内定义组件,对于 React 函数式组件,不要在函数体中定义组件。 (18认同)
  • 我认为这是我的问题,但是由于对`this`的引用,我无法将组件移至`render()`之外,而`class ...扩展了Component`。例如`onChange = {this.handleInputChange}` (2认同)
  • 谢谢!你救了我的屁股!! (2认同)
  • @Wong Jia Hau:当你在 React 功能组件的函数体中定义组件时会发生什么?我也遇到了类似的问题,按照您的建议解决了。 (2认同)

小智 17

我所做的只是将valueprop 更改为defaultValue,第二个更改是将onChangeevent 更改为onBlur


ilk*_*ran 15

我用钩子也有同样的症状。然而我的问题是在父级内部定义一个组件。

错误的:

const Parent =() => {
    const Child = () => <p>Child!</p>
    return <Child />
}
Run Code Online (Sandbox Code Playgroud)

对:

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

Run Code Online (Sandbox Code Playgroud)

  • 请注意,您仍然可以通过常规函数调用来使用此类嵌套子级。例如,“return &lt;div&gt;{Child()}&lt;/div&gt;”就可以了,尽管不可否认有点难看。有时我发现将 JSX 表达式的不可重用部分提取到本地闭包中以提高可读性很有帮助,而不必使它们成为完整的独立组件并传递大量 props。焦点行为有点棘手。 (4认同)
  • 只是为了扩展 @ilkerkaran 所说的内容,因为 React 将在每次状态更新时运行组件函数(“Parent”函数),所以每次渲染时,内部“Child”的值都会不同。因此,React 无法在每次渲染中重用您的子组件,并且每次更新您最终都会得到新元素。 (3认同)
  • 每次父级重新渲染时,它都会**挂载**子级 (2认同)

Sha*_*jan 8

我的答案类似于@ z5h所说的。

就我而言,我曾经为组件Math.random()生成唯一key的。

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

删除那对我来说很有效。

PS:我本可以对此发表评论,但是对此我没有足够的声誉。

  • 像 https://www.npmjs.com/package/shortid 这样的模块也是处理此类问题的好方法。 (2认同)

spa*_*mad 6

在只有一个输入需要聚焦的情况下,将autoFocus属性应用于input元素可以作为一种变通方法。在这种情况下,key属性将是不必要的,因为它只是一个元素,而且您不必担心将input元素分解为它自己的组件以避免失去对重新渲染主组件的关注。


chr*_*eyn 5

我有同样的行为。

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

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

...

render = () => {
    return <div>{ example }</div>
}
Run Code Online (Sandbox Code Playgroud)

每次更新父元素时,此嵌套数组中的每个元素都会重新呈现。所以每次输入都会丢失“ref”道具

我修复了将内部数组转换为反应组件(具有渲染功能的函数)的问题

const example = [
            <myComponentArray />
        ]

 ...

render = () => {
    return <div>{ example }</div>
}
Run Code Online (Sandbox Code Playgroud)

编辑:

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

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

const ParentComponent = (props) => (
    <React.Fragment>
        <SomeComponent ... />
        <div />
    </React.Fragment>
);
Run Code Online (Sandbox Code Playgroud)


小智 5

我解决了同样的问题,删除了输入及其父元素中的关键属性

// 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)
    }}
/>
Run Code Online (Sandbox Code Playgroud)