防止在React JS中多次调用方法

时间:2016-12-24 23:33:37

标签: javascript reactjs

我正在尝试通过实现Thinking in React来试验reactjs多字段组件,但无法弄清楚为什么这里的子方法被多次调用。



var i = 0;
class SearchBar extends Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(key) {
    //this method is called multiple times during Render()
    console.log(i++);
    return function(e) {
      var value = key !== 'inStockOnly' ? e.target.value : e.target.checked;
      this.props.onUserInput(
        key,
        value
      );
    }.bind(this);
  }

  render() {    
    return (
      <form>
        <input type="search" value={this.props.filterText} placeholder="Search ..." ref={(input) => {input.focus();}} onChange={this.handleChange('filterText')} />
        <p>
        <input type="checkbox" checked={this.props.inStockOnly} onChange={this.handleChange('inStockOnly')} />
        {' '}
        Only show products in stock
        </p>
      </form>
    );
  }
}

class FilterableProducts extends Component {
constructor(props) {
  super(props);
  this.state = {
    filterText: '',
    inStockOnly: false
  };
  this.handleInput = this.handleInput.bind(this);
}
handleInput(key, value) {
/*var state = {};
  state[key] = value;  
  console.log(state);
  this.setState(state);*/

  //above is what I am trying to do later on but still stuck on why setState does not work
  //test
  this.setState({
    filterText: 'foo',
    inStockOnly: true
  });
}
  render() {
    return (      
      <SearchBar filterText={this.state.filterText} inStockOnly={this.state.inStockOnly} onUserInput={this.handleInput} />            
    );
  }
}
&#13;
&#13;
&#13; 的更新

&#13;
&#13;
//updated handleChanged
handleChange(key, e) {
      var value = key !== 'inStockOnly' ? e.target.value : e.target.checked;
      this.props.onUserInput(
        key,
        value
      );
}

//updated handleInput
handleInput(key, value) {
  //var state = {};
  //state[key] = value;
  //this.setState(state);
  //console.log(state);
  //above is what I am trying to do
  //test
  this.setState({
    filterText: 'g',
    inStockOnly: true
  });
}
&#13;
<!--i changed the event listener to this
  now its not called directly
-->
<input type="search" value={this.props.filterText} placeholder="Search ..." ref={(input) => {input.focus();}} onChange={(e)=>this.handleChange('filterText', e)} />
&#13;
&#13;
&#13;

任何建议表示赞赏

2 个答案:

答案 0 :(得分:1)

编辑:这是正确的,它们应该立即被调用,因为你正在返回一个与onChange绑定的函数。内部函数只会被称为onChange。您需要传递密钥。

第二次修改

handleInput(event) {
  this.setState({
    filterText: event.target.value,
    inStockOnly: true
  });
}
<input type="search" value={this.state.filterText} placeholder="Search ..." ref={(input) => {input.focus();}} onChange={this.handleInput} />

原创

handleChange(key) {
    //this method is called multiple times during Render()
    console.log(i++);
    return function(key, event) {
      var value = key !== 'inStockOnly' ? event.target.value : event.target.checked;
      this.props.onUserInput(
        key,
        value
      );
    }.bind(this);
}

事件将在触发时作为最后一个参数传递。

setState什么不起作用?您在handleInput中正确使用它。

注释掉的setState不会起作用。您应该只在构造函数中创建状态,并且还要注意,设置状态后console.log()可能仍然是空的,因为setState对于性能是异步的,并且可能直到稍后才更新。

var state = {};
state[key] = value;  
console.log(state);
this.setState(state);*/

您需要componentDidUpdate代替并在其中执行console.log或使用setState的回调,即this.setState({state[key]: value}, function() {console.log(this.state)});,它将始终提供正确的状态。

答案 1 :(得分:0)

刚刚发现为什么我的'setState'“不工作”。这是因为没有正确使用ref属性。通过删除ref={(input) => {input.focus();}},代码将起作用。在我的情况下,我可以将其更改为ref={(input) => if(input === null) return; {input.focus();}}将保持焦点功能。这是因为ref函数被调用两次:whenMountdidMount

如此全功能的方法将是:

class SearchBar extends Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(key, e) {
      var value = key !== 'inStockOnly' ? e.target.value : e.target.checked;
      this.props.onUserInput(
        key,
        value
      );
  }

  render() {
    return (
      <form>
        <input type="search" value={this.props.filterText} placeholder="Search ..." ref={(input) => {if(input === null) return;input.focus();}} onChange={(e)=>this.handleChange('filterText', e)} />
        <p>
        <input type="checkbox" checked={this.props.inStockOnly} onChange={(e)=>this.handleChange('inStockOnly', e)} />
        {' '}
        Only show products in stock
        </p>
      </form>
    );
  }
}

class FilterableProducts extends Component {
constructor(props) {
  super(props);
  this.state = {
    filterText: '',
    inStockOnly: false
  };
  this.handleInput = this.handleInput.bind(this);
}
handleInput(key, value) {
  var state = {};
  state[key] = value;
  this.setState(state);
}
  render() {
    return (      
      <SearchBar filterText={this.state.filterText} inStockOnly={this.state.inStockOnly} onUserInput={this.handleInput} />      
    );
  }
}

使用onChange={(e)=>this.handleChange('inStockOnly', e)} />onChange={(e)=>this.handleChange('filterText', e)}我们可以避免在多个字段中使用很多ref组件