web-dev-qa-db-ja.com

React ES6では、文字を入力した後に入力フィールドがフォーカスを失うのはなぜですか?

以下の私のコンポーネントでは、入力フィールドは文字を入力した後にフォーカスを失います。 Chromeのインスペクターを使用していると、入力時に入力フィールドの値属性だけではなく、フォーム全体が再レンダリングされているように見えます。

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;
15
spunge

何が起こっているのですか?

OnChangeイベントが発生すると、コールバックは新しいタイトル値でsetStateを呼び出します。この値は、小道具としてテキストフィールドに渡されます。その時点で、Reactはそれを新たにレンダリングします。これがフォーカスを失う理由です。

私の最初の提案は、コンポーネントのキー、特にフォームと入力自体を提供することです。キーはReact=を介してコンポーネントのアイデンティティを保持することを許可します。

編集:

キーに関するこのドキュメントを参照してください: https://reactjs.org/docs/lists-and-keys.html#keys

11
Ezra Chang

私はReactが初めてで、この問題に直面しています。

これが私が解決するためにしたことです:

  1. 最初にすべてのコンポーネントをコンポーネントフォルダに移動してから、使用する場所にインポートします
  2. すべてのフォーム要素がnameおよびidプロパティを取得するようにしてください
  3. ツリーを上るときにすべてのコンポーネントが一意のkeyを取得することを確認してください

私よりも賢い人なら、おそらくステップ1をスキップしてすべてをインラインに保つことができる理由を教えてくれるかもしれませんが、これはコードの整理に役立ちました。

本当の問題はReactがすべてを再描画している(既に述べたように)であり、その再描画はkeyを持たないが必要な親コンポーネントで行われることがあると思います。

私の問題は、フォーム入力用のカスタムコンポーネントをラップするExpansionPanelコンポーネントにありました。パネルにはkeyも必要でした!

これが他の誰かに役立つことを願っています、これは私を夢中にさせていました!

1
Nateous

これは、render()内の関数でフォームをレンダリングしているためです。

状態/プロップが変更されるたびに、関数は新しいフォームを返します。それはあなたが焦点を失う原因となりました。

関数内にあるものをレンダリングに直接入れてみてください。

       <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>
1
Alex Yan

私の問題は、同じファイル内のステートレスコンポーネントで再レンダリングすることでした。そのため、不要なステートレスコンポーネントを削除し、コードを直接挿入するだけで、不要な再レンダリングはありませんでした。

render(){
   const NewSocialPost = () => 
       <div className='new-post'>
           <input
                onChange={(e) => this.setState({ newSocialPost: e.target.value })}
                value={this.state.newSocialPost}/>
           <button onClick={() => this._handleNewSocialPost()}>Submit</button>
      </div>

return (
            <div id='social-post-page'>
                <div className='post-column'>
                    <div className='posts'>
                        <Stuff />
                    </div>
                    <NewSocialPost />
                </div>
                <MoreStuff />
            </div>
1

状態を変更するonChangeメソッドがあるため、文字を入力するとフォームが再レンダリングされます。状態が変化するたびにフォームが再レンダリングされるため、入力メソッドがフォーカスを失います。

Reduxを使用しているため、最良の方法は投稿タイトルの値をreduxオブジェクトに保存することです。また、フォームで redux-form を使用することもできます。

re-renderingなしで入力の値を取得するには、 refs を使用する必要があります。

私はコメントする権限がありません、それは答えでなければなりません。私は同様の問題を抱えていて、Alex Yanからの回答は共同でした。

つまり、私はその機能を持っていました

const DisplaySearchArea =()=>{return (arrayOfSearchFieldNames.map((element, index)=>{return(<div key ={index} className = {inputFieldStyle}><input  placeholder= {arrayOfPlaceholders[index]} type="text" className='border-0'
value={this.state[element]}
onChange={e => {this.setState({ [element]: e.target.value }); console.log(e.target)}}
onMouseEnter={e=>e.target.focus()}/></div>)}))}

Chromeとしてレンダリングされた場合<DisplaySearchArea />としてではなくFFで問題なく動作します。{...}としてレンダリングされた場合、両方で問題ありません。 、すでにラムダを使いすぎる傾向があると言われています。

0