簡體   English   中英

警告控制組件更改為不受控制

[英]Warning Controlled Component Changing to Uncontrolled

我有兩個隱藏的輸入字段,當節點提取完成並且設置值沒有問題時,將使用prop中的值填充這些輸入字段,但是我看到以下警告。

Warning: A component is changing a controlled input of type hidden to be uncontrolled. Input elements should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.

雖然我了解了受控和不受控制之間的區別,但似乎無法理解為什么我的組件會在兩者之間造成沖突。 我的組件代碼中是否有可能導致此問題的明確信息?

import React from 'react';
import isEqual from 'lodash/isEqual';

export default class DateFilter extends React.Component {
    constructor(props) {
        super(props);
        this.state = { 
            startDateValue: '',
            endDateValue: ''
        };
    }

    componentDidMount() {
        this.setState({
            startDateValue: this.props.startDateQuery,
            endDateValue: this.props.endDateQuery
        });
    }

    handleChange(input, value) {
        this.setState({
            [input]: value
        })
    }

    componentWillReceiveProps(nextProps) {
        if (!isEqual(this.props, nextProps)){
            this.setState({ startDateValue: nextProps.startDateQuery, endDateValue: nextProps.endDateQuery });
        }
    }

    render() {
        return (
            <div className="col-md-3">
                <input type="hidden" name="_csrf" value={this.props.csrf} />
                <div className="input-group blog-filter-date-range-picker">
                    <p>Blog Date Range:</p>
                </div>
                <div className="input-group blogFilterDatePicker">
                    <span className="input-group-addon"><i className="glyphicon glyphicon-calendar"></i></span>
                    <input type="text" name="blogDateRange" className="form-control blogFilterDatePicker" autoComplete="off" />
                </div>
                <input type="hidden" name="blogStartDate" className="form-control" value={this.state.startDateValue} onChange={e => this.handleChange('startDateValue', e.target.value)} />
                <input type="hidden" name="blogEndDate" className="form-control" value={this.state.endDateValue} onChange={e => this.handleChange('endDateValue', e.target.value)} />
            </div>
        );
    }
}

父組件:

import React from 'react';

import CatgoryFilter from './SearchFormFilters/CategoryFilter';
import DepartmentFilter from './SearchFormFilters/DepartmentFilter';
import TeamFilter from './SearchFormFilters/TeamFilter';
import TypeFilter from './SearchFormFilters/TypeFilter';
import DateFilter from './SearchFormFilters/DateFilter';

//Activity Feed - Search Form
export default class ActivityFeedSearchForm extends React.Component {
    render() {
        var clearFilters;
        if(this.typeQuery || this.props.categoryQuery || this.props.departmentQuery || this.props.teamQuery || this.props.startDateQuery || this.props.endDateQuery || this.props.typeQuery){
            clearFilters = <a href="/app" id="clear-filter">Clear</a>;
        }

        return (
            <div className="row">
                <div className="annotation-search-form col-md-10 col-md-offset-1">
                    <div clas="row">
                        <form action="/app" method="post" className="annotation-filter-fields">
                            <DateFilter csrf={this.props.csrf} startDateQuery={this.props.startDateQuery} endDateQuery={this.props.endDateQuery} />
                            <TypeFilter typeQuery={this.props.typeQuery} />
                            <CatgoryFilter category={this.props.category} categoryQuery={this.props.categoryQuery} />
                            <DepartmentFilter department={this.props.department} departmentQuery={this.props.departmentQuery} />
                            <TeamFilter team={this.props.team} teamQuery={this.props.teamQuery} />
                            <div className="col-md-1 annotation-filter-section filter-button-container">
                                <button type="submit" id="annotation-filter-submit">Filter</button>
                                {clearFilters}
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        )
    }
}

頂級父組件:

import React from 'react';
import fetch from 'node-fetch';
import ReactMarkdown from 'react-markdown';
import path from 'path';
import ActivityFeedSearchForm from './ActivityFeedSearchForm/ActivityFeedSearchForm';
import { API_ROOT } from '../config/api-config';

//GET /api/test and set to state
export default class ActivityFeed extends React.Component{
    constructor(props, context) {
        super(props, context);
        this.state = this.context.data || window.__INITIAL_STATE__ || { team: [] };
    }

    fetchList() {
            fetch(`${API_ROOT}` + '/api' + window.location.search, { compress: false })
                .then(res => {
                    return res.json();
                })  
                .then(data => {
                    this.setState({ 
                        startDateQuery: data.startDateQuery,
                        endDateQuery: data.endDateQuery,
                    });
                }) 
                .catch(err => {
                    console.log(err);
                });
        }

    componentDidMount() {
        this.fetchList();
    }

    render() {  
            return (
                <div>
                    <Navigation notifications={this.state.notifications}/>
                    <ActivityFeedSearchForm csrf={this.state.csrf} category={this.state.category} categoryQuery={this.state.categoryQuery} department={this.state.department} departmentQuery={this.state.departmentQuery} team={this.state.team} teamQuery={this.state.teamQuery} typeQuery={this.state.typeQuery} startDateQuery={this.state.startDateQuery} endDateQuery={this.state.endDateQuery} />
                    <div className="activity-feed-container">
                        <div className="container">
                            <OnboardingInformation onboarding={this.state.onboardingWelcome} />
                            <LoadingIndicator loading={this.state.isLoading} />
                            <ActivityFeedLayout {...this.state} />
                        </div>
                    </div>
                </div>
            )
    }
};

當您只處理componentWillReceiveProps中的startDateValue和endDateValue時,最好將它們而不是整個道具進行比較。 整個道具沒有進行深度平等檢查,這就是為什么您得到警告

更改

    componentWillReceiveProps(nextProps) {
    if (!isEqual(this.props, nextProps)){
        this.setState({ startDateValue: nextProps.startDateQuery, endDateValue: nextProps.endDateQuery });
    }
}

    componentWillReceiveProps(nextProps) {
    if (this.props.startDateQuery != nextProps.startDateQuery && this.props.endDateQuery != nextProps.endDateQuery){
        this.setState({ startDateValue: nextProps.startDateQuery, endDateValue: nextProps.endDateQuery });
    }
}

另外,您也不需要componentDidMount,因此請刪除代碼中的該部分,並使用下面的內容更新構造函數代碼

     constructor(props) {
         super(props);
         this.state = { 
              startDateValue: this.props.startDateQuery ? this.props.startDateQuery: '',
               endDateValue:this.props.endDateQuery ? this.props.endDateQuery:  ''
         };
        }
    }

更改

     <input type="hidden" name="_csrf" value={this.props.csrf} />

      <input type="hidden" name="_csrf" value={this.props.csrf ? this.props.csrf : "" />

而且您沒有綁定handleChange,因此可以在構造函數中手動將其綁定或將其更改為箭頭功能,如下所示

更改

    handleChange(input, value) {
    this.setState({
        [input]: value
    })
}

    handleChange = (input, value) => {
    this.setState({
        [input]: value
    })
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM