在 React ES6 中,为什么输入字段在输入字符后失去焦点?

IT技术 reactjs text input ecmascript-6 focus
2021-04-11 06:03:07

在我下面的组件中,输入字段在输入字符后失去焦点。在使用 Chrome 的 Inspector 时,看起来整个表单都在重新呈现,而不仅仅是输入字段的 value 属性。

我从 eslint 和 Chrome Inspector 都没有收到错误消息。

当表单位于渲染的返回中或作为单独的组件导入时,提交表单本身就像实际输入字段一样工作,但不是我在下面编码的方式。

为什么会这样?

主页组件

import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as actionPost from '../redux/action/actionPost';
import InputText from './form/InputText';
import InputSubmit from './form/InputSubmit';

class _PostSingle extends Component {
    constructor(props, context) {
        super(props, context);
        this.state = {
            post: {
                title: '',
            },
        };
        this.onChange = this.onChange.bind(this);
        this.onSubmit = this.onSubmit.bind(this);
    }
    onChange(event) {
        this.setState({
            post: {
                title: event.target.value,
            },
        });
    }
    onSubmit(event) {
        event.preventDefault();
        this.props.actions.postCreate(this.state.post);
        this.setState({
            post: {
                title: '',
            },
        });
    }
    render() {
        const onChange = this.onChange;
        const onSubmit = this.onSubmit;
        const valueTitle = this.state.post.title;
        const FormPostSingle = () => (
            <form onSubmit={onSubmit}>
                <InputText name="title" label="Title" placeholder="Enter a title" onChange={onChange} value={valueTitle} />
                <InputSubmit name="Save" />
            </form>
        );
        return (
            <main id="main" role="main">
                <div className="container-fluid">
                    <FormPostSingle />
                </div>
            </main>
        );
    }
}

_PostSingle.propTypes = {
    actions: PropTypes.objectOf(PropTypes.func).isRequired,
};

function mapStateToProps(state) {
    return {
        posts: state.posts,
    };
}

function mapDispatchToProps(dispatch) {
    return {
        actions: bindActionCreators(actionPost, dispatch),
    };
}

export default connect(mapStateToProps, mapDispatchToProps)(_PostSingle);

文本输入组件

import React, { PropTypes } from 'react';

const InputText = ({ name, label, placeholder, onChange, value, error }) => {
    const fieldClass = 'form-control input-lg';
    let wrapperClass = 'form-group';
    if (error && error.length > 0) {
        wrapperClass += ' has-error';
    }
    return (
        <div className={wrapperClass}>
            <label htmlFor={name} className="sr-only">{label}</label>
            <input type="text" id={name} name={name} placeholder={placeholder} onChange={onChange} value={value} className={fieldClass} />
            {error &&
                <div className="alert alert-danger">{error}</div>
            }
        </div>
    );
};

InputText.propTypes = {
    name: PropTypes.string.isRequired,
    label: PropTypes.string.isRequired,
    placeholder: PropTypes.string.isRequired,
    onChange: PropTypes.func.isRequired,
    value: PropTypes.string,
    error: PropTypes.string,
};

InputText.defaultProps = {
    value: null,
    error: null,
};

export default InputText;

提交按钮组件

import React, { PropTypes } from 'react';

const InputSubmit = ({ name }) => {
    const fieldClass = 'btn btn-primary btn-lg';
    return (
        <input type="submit" value={name} className={fieldClass} />
    );
};

InputSubmit.propTypes = {
    name: PropTypes.string,
};

InputSubmit.defaultProps = {
    name: 'Submit',
};

export default InputSubmit;
6个回答

这是因为您在 render() 内的函数中渲染表单。

每次您的 state/prop 更改时,该函数都会返回一个新表单。它导致你失去焦点。

尝试将函数内部的内容直接放入渲染中。

<main id="main" role="main">
    <div className="container-fluid">
        <FormPostSingle />
    </div>
</main>

===>

<main id="main" role="main">
    <div className="container-fluid">
        <form onSubmit={onSubmit}>
            <InputText name="title" label="Title" placeholder="Enter a title" onChange={onChange} value={valueTitle} />
            <InputSubmit name="Save" />
        </form>
    </div>
</main>
所以我猜你是对的,但你不能直接把元素放进去的原因很可能是因为你这样做的全部原因是为了重复使用不止一个。如果你想要多个FormPostSingle组件,你会怎么做
2021-06-04 06:03:07
对于函数组件的人来说,这意味着不要在你的函数组件体内定义组件......基本上每个组件都将位于module的顶层(即使你在一个module中有多个)......我使用 func 中的样式组件定义解决了这个问题。补偿 看起来像一个表达式,但当然它实际上是在奇怪的(对我来说)样式化的组件模板文字语法中调用一个函数。oop!
2021-06-05 06:03:07
不知道为什么这在正确时被否决了。正是匿名函数 FormPostSingle 导致了这个问题,因为它在渲染内部声明了一个新函数,每次渲染运行时都会创建一个带有新函数签名的新函数,这导致 React 无法跟踪它创建的元素。
2021-06-05 06:03:07
@Nateous 我的意思是。“不要在渲染函数下创建你的表单函数”,如果你想重用一个表单组件,你应该创建一个单独的函数/组件文件并使用它。
2021-06-08 06:03:07
这个答案很有帮助,我把它变成了一个函数调用{FormPostSingle(props)},它立即起作用。我不知道你在说什么渲染函数,因为我使用钩子
2021-06-13 06:03:07

这发生在我身上,虽然我设置了钥匙!

原因如下:

我正在使用文本字段中的键。在同一个区块内;我有一个输入字段来更新同一文本字段的值。现在,由于组件键发生了变化,react 会重新渲染 UI。因此失去焦点。

从中得到什么:

不要使用不断变化的键。

太棒了,很高兴知道它有帮助👍
2021-06-10 06:03:07
感谢您的回答。它解决了这个问题,这是我使用 React 分配的第一个任务。
2021-06-19 06:03:07

正在发生的事情是这样的:

当您的 onChange 事件触发时,回调会使用新的标题值调用 setState,该值会作为props传递到您的文本字段。此时,React 会渲染一个新组件,这就是您失去焦点的原因。

我的第一个建议是提供您的组件键,尤其是表单和输入本身。键允许 React 通过渲染保留组件的身份。

编辑:

请参阅有关密钥的此文档:https : //reactjs.org/docs/lists-and-keys.html#keys

“提供您的组件密钥”是什么意思?你有任何文档的链接吗?
2021-05-28 06:03:07
正确解释原因,但关键建议不能解决问题。对于任何无法弄清楚为什么解决方案对他们不起作用的人,仅供参考。
2021-06-10 06:03:07
对于它可能有帮助的人,这也可能是因为在不需要密钥的地方使用了密钥。我在表的主体上有 key={Math.random()} ,然后有动态行,这导致了这个错误。
2021-06-12 06:03:07
拥有一个不断变化的关键属性会导致一个组件总是被重新渲染,而不是被差异化并只重新渲染改变的部分。
2021-06-12 06:03:07
@GavinMannion 这对我有用!你能更详细地解决它吗?为什么人们总是有这行代码?
2021-06-15 06:03:07

遇到了同样的问题并以一种快速简单的方式解决了它:只需调用组件{compName()}而不是<compName />

例如,如果我们有:

const foo = ({param1}) => {
   // do your stuff
   return (
      <input type='text' onChange={onChange} value={value} />
   );
};

const main = () => (
   <foo param1={true} />
);

然后,我们只需要改变我们调用foo()组件的方式:

const main = () => (
   {foo({param1: true})}
);
非常感谢你的这个黑色魔法!
2021-05-26 06:03:07
疯了吧!我很高兴我找到了这个答案。太感谢了。@m_wer 谢谢你的解释。
2021-06-04 06:03:07
这种变化也对我有用。我想知道这是什么原因?
2021-06-07 06:03:07
非常感谢你。这让我发疯了,所以我不得不研究为什么会发生这种情况。如果您仍然感兴趣,这里有一个解释@Normal:链接
2021-06-08 06:03:07
多么奇怪和烦人,谢谢你的提示,这对我也有用!我之前使用过 foo(),但将其更改为 <Foo />。我不得不把它改回来才能让我的输入再次工作。
2021-06-21 06:03:07

您必须为输入组件使用唯一键。

<input key="random1" type="text" name="displayName" />

key="random1" 不能随机生成。例如,

<div key={uuid()} className='scp-ren-row'>

uuid() 将为每次重新渲染生成一组新的字符串。这将导致输入失去焦点。

如果元素是在 .map() 函数中生成的,则使用索引作为键的一部分。

{rens.map((ren,i)=>{
    return(
    <div key={`ren${i+1}`} className='scp-ren-row'>
       {ren}{i}
</div>)
}

这将解决问题。

@Dave 帮助我摆脱了一个痛苦的错误,谢谢!
2021-05-23 06:03:07
谢谢,您的解决方案确实解决了我的问题。我是用uuidv4来生成密钥的。
2021-05-28 06:03:07
这真的很有帮助,爱你!!
2021-06-02 06:03:07
我正在使用随机生成的密钥,uuid()但它不起作用,现在它起作用了...谢谢!
2021-06-03 06:03:07