选项选择的道具或状态

时间:2019-01-06 13:16:27

标签: reactjs

我试图了解如何使用道具或状态识别页面加载时的选定选项。我了解到React在value标签上使用了defaultValue<select>来为受控状态建立selected的值,并且我知道不受控制的状态更灵活,但不是推荐的。在当前代码中,我正在尝试设置受控状态值,但是有两个问题使设置不正确。

1)我有一个属性,该属性的值应定义页面加载时最初选择的值,但是我知道我无法将其设置为状态值,因此它不适合受控环境设置。

2)当我将prop设置为value时,我看到了页面加载时选择的值,但是我无法从下拉列表中选择其他选项。它没有改变,这使我相信,如果我使用的是受控环境,则需要使用状态。

根据以上信息,最佳解决方案是什么?我也很好奇,如果我切换到不受控制的设置会如何解决。根据我的信息会更好吗?任何帮助将不胜感激。

代码(请注意,由于在这种情况下使用了prop,因此我并未使用该状态,但是以前使用和显示该状态是为了可视化所尝试的两种方法)

import React from 'react';

export default class CategoryFilter extends React.Component {
    constructor(props) {
        super(props);
        this.state = {value: ''};
        this.handleChange = this.handleChange.bind(this);
    }

    handleChange(event) {
        this.setState({value: event.target.value});
        console.log(this.state.value)
    }

  render() {
    console.log("CategoryFilter");
    console.log(this.props);
    console.log(this.state.value);
    return (
        <div className="col-md-2 annotation-filter-section">
            <p>Category:</p>
            <select name="category" className="form-control annotation-filter-category" value={this.props.categoryQuery} onChange={this.handleChange}>
                <option value=""></option>
                {
                    this.props.category.map(
                        (category) => { 
                                return ( <option key={category.categoryIdHash} value={category.categoryIdHash}>{category.categoryName}</option> ) 
                            }
                        )
                }
            </select>
        </div>
    );
  }
}

代码一级升级:

export default class SearchForm extends React.Component {
    render() {
        return (
            <CatgoryFilter category={this.props.category} categoryQuery={this.props.categoryQuery} />
        )
    }
}

父组件:

export default class FeedContainer extends React.Component{
    constructor(props, context) {
        super(props, context);
        this.state = this.context.data || window.__INITIAL_STATE__;
    }

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

    }

    componentDidMount() {
        this.fetchList();
    }

    render() { 
        return (
            <SearchForm category={this.state.category} categoryQuery={this.state.categoryQuery} />
        )
    }
}

2 个答案:

答案 0 :(得分:2)

如果要传递初始值,然后让组件处理自己的状态,这是一种方法:

import React, { Component } from 'react';
import { render } from 'react-dom';

class App extends Component {
  constructor(props) { 
    super(props);
    this.state = { 
      value: props.initialValue,
    }
  }

  handleChange = (e) => {
    const { value } = e.target;
    this.setState({ value });
  }

  render() {
    const { value } = this.state;

    return (
      <React.Fragment>
        <input
          onChange={this.handleChange}
          value={value} />
      </React.Fragment>
    );
  }
}

render(<App initialValue="Hello"/>, document.getElementById('root'));

实时示例here

如果有必要,您可以提升状态并传递处理程序:

import React, { Component } from 'react';
import { render } from 'react-dom';

const Child = ({ value, handleChange }) => (
  <input value={value} onChange={handleChange} />
)

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      value: props.initialValue,
    }
  }

  handleChange = (e) => {
    const { value } = e.target;
    this.setState({ value });
  }

  render() {
    const { value } = this.state;

    return (
      <Child handleChange={this.handleChange} value={value} />
    );
  }
}

render(<App initialValue="Hello" />, document.getElementById('root'));

实时示例here

答案 1 :(得分:1)

由于您是从获取请求中获取categoryQuery的,因此您可能无法获取组件安装时间的值,因此需要使用componentWillReceiveProps生命周期方法,如下所示

import React from 'react';
import isEqual from 'lodash/isEqual';
export default class CategoryFilter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { value: '' };
    this.handleChange = this.handleChange.bind(this);
  }
  componenetDidMount() {
   this.setState({value:this.props.categoryQuery})
  }
  componentWillReceiveProps(nextProps) {
    if (!isEqual(this.props, nextProps)) {
      this.setState({ value: nextProps.categoryQuery })
    }
  }

  handleChange(event) {
    this.setState({ value: event.target.value });
    console.log(this.state.value)
  }

  render() {
    console.log("CategoryFilter");
    console.log(this.props);
    console.log(this.state.value);
    return (
      <div className="col-md-2 annotation-filter-section">
        <p>Category:</p>
        <select name="category" className="form-control annotation-filter-category" value={this.props.categoryQuery} onChange={this.handleChange}>
          <option value=""></option>
          {
            this.props.category.map(
              (category) => {
                return (<option key={category.categoryIdHash} value={category.categoryIdHash}>{category.categoryName}</option>)
              }
            )
          }
        </select>
      </div>
    );
  }
}

您可以使用lodash中的isEqual来比较道具。您需要将nextProps和this.props进行比较,因为props发生任何更改(导致状态更改)时都会触发componentWillReceiveProps生命周期方法。将会导致无限的重新渲染。最好使用componentDidUpdate,因为不赞成componentWillReceiveProps。