Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
243 views
in Technique[技术] by (71.8m points)

javascript - How do I handle one input being controlled by two components in React?

I am trying to implement an autocomplete functionality to the input fields of the form (for adding meetings to the calendar). Simplified structure of components looks like this: CalendarForm > Autocomplete > FromInput + AutocompleteSuggestions (4 of each).

CalendarForm

Autocomplete

FromInput and AutocompleteSuggestions (both on the same level)

User should be able to type in 2 letters, the suggestions are then fetched from json-database and displayed underneath the input filed.

Each input value is stored in state in CalendarFrom via handleChange() method.

I am receiving value via props in FromInput (from CalendarForm in inputAutcomplete method) and passing it to the render method in as value={ value }. After user selects the suggestion by clicking on it, the input value should be replaced with the suggestion. Instead it is being changed from uncontrolled to controlled, which causes a warning.

Current behaviour: value in props in FormInput is undefined while it should be equal to whatever suggestion user has picked.

Expected behaviour: User picks suggestion from the rendered list and the suggestion is then set as value in this certain input. I am looking for the 'proper' solution and trying to understand mechanics behind this functionality.

This is my first react project so I kindly ask for forgiveness if the post isn't super clear. I did my best explaining what I need and I am happy to answer follow up questions.

Here is the simplified code:

CalendarForm.js

export default class CalendarForm extends Component {
    constructor(props) {
        super(props)
        this.api = new API();
        this.state = {
            ...this.initializeEmptyState(),
            errors: []
        }
    }
inputAutcomplete(inputKey, attributes) {
        return (
            <Autocomplete
                    value={ this.state[inputKey] }
                    onChange={ this.handleCompletion }
                >
                    <FormInput
                        { ...attributes }
                        onChange={ this.handleChange }
                        value={ this.state[inputKey] } // should it be this.props.usersSelection?

                    />
            </Autocomplete>
            )
    }
displayFormFields = () => {
        const { formFields } = this.props;
        const allFields = formFields.map(field => {
            const { name, placeholder, label, isAutocomplete } = field;
            return (
                    <div key={ name }>
                        <label className={ placeholder }>
                            <h2 className="calendar__form-input-header">{ label }</h2>
                            { (isAutocomplete) ? 
                                this.inputAutcomplete(name, field)
                                :
                                this.inputRegular(name, field)
                            }
                        </label>
                    </div>
            )
        });
        return allFields;
    }
render() {
        return (
            <div className="calendar__form-component">
                <form
                    onSubmit={ this.handleSubmit }
                    className="calendar__form"
                >
                    { this.displayFormFields() }
                    <button className="calendar__form-submit-btn" type="submit">Add meeting!</button>
                </form>
            </div>
        )
    }

Autocomplete.js

export default class Autocomplete extends Component {
    constructor(props) {
        super(props)
        this.api = new Api();
        this.state = {
            records: [],
            displayRecords: true
        };
    }
handleKeyUp = e => {
        const { name, value } = e.target;
        this.getSuggestions(name, value);
    }
handleSuggestionSelect = e => {
        const userPick = e.target.innerText;
        this.props.onChange(e)
    }
render() {
        return (
            <div
                className="calendar__form-autocomplete"
                onKeyUp={ this.handleKeyUp }
            >
                    { this.props.children }
                <AutocompleteSuggestions 
                    suggestions={ this.state.records }
                    handleSuggestion={ this.handleSuggestionSelect }    
                />
            </div>
        )
    }

FormInput.js

export default class FormInput extends Component {
    constructor(props) {
        super(props);
        this.state = {
            value: this.props.value
        }
    }
    render() {
        const { name, className, onChange, placeholder, type, value, autocomplete } = this.props;
        return (
            <input
                className={ className }
                placeholder={ placeholder }
                type={ type }
                onChange={ onChange }
                name={ name }
                value={ value }
                autoComplete={ autocomplete }
            />
        )
    } 
}

AutocompleteSuggestions.js

export default class AutocompleteSuggestions extends Component {

    render() {
        const { suggestions } = this.props;
        const suggestionsList = suggestions.map(suggestion => {
            return (
                <li
                    className="calendar__form-input-suggestion"
                    onClick={ this.props.handleSuggestion }
                    key={ suggestion }
                >{ suggestion }</li>
                    )
        })
        return (
            <ul className="calendar__form-input-suggestion-list">
                { suggestionsList }
            </ul>
        )
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
等待大神答复

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...