创建可以在不创建新组件的情况下传递参数的函数

时间:2017-09-15 13:14:50

标签: javascript function reactjs bind

我的问题是React对渲染函数中绑定函数的问题。

以下不是好习惯:

render() {
   <div onClick={this.callFunction.bind(this)}/>
}

因为每次重新渲染都会向页面添加一个新函数,最终导致浏览器内存不足。

解决方案是这样做:

constructor() {
   this.callFunction = this.callFunction.bind(this);
}

render() {
   <div onClick={this.callFunction}/>
}

这个问题是当我想将值传递给函数时。

我知道我可以将div作为子组件,并通过callBack传递参数,但如果div仅在整个应用程序中使用一次,这似乎不合理。我接受我可以做这项工作,但这不是这个问题的范围。

我也知道这个解决方案:

render() {
   <div onClick={() => this.callFunction.call(this, param)}/>
}

没有更好,因为它仍然在创造一个新功能。

所以我的问题是,我如何创建一个函数,我可以在不创建新组件的情况下将参数传递给它,并且不在每个渲染上绑定新的函数?

4 个答案:

答案 0 :(得分:1)

您可以将function* foo(){ var a = 0, c while(a < 10){ a += 1 yield a //if the semicolon is added here, the final result is 1 [c] = [101] } } var gen= foo() console.log(gen.next().value) // [101] 的声明更改为箭头函数,这会隐含地绑定范围,如下所示:

callFunction

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

然后您的原始渲染功能将按预期工作!

答案 1 :(得分:1)

您无法避免创建第二个组件,因为您需要将函数引用作为事件处理程序传递,这将在事件触发时由浏览器执行。

所以问题不在于绑定,而在于需要传递引用,而引用无法接收参数。

修改
顺便说一下,如果你不喜欢绑定或匿名箭头功能的语法和噪音,你可以使用currying 如果您觉得有趣,我在different question中发布了一个示例。这不会解决问题,它只是另一种传递新参考的方法(我发现它是最简洁的)

答案 2 :(得分:0)

使用副作用

副作用是函数使用来自外部但不作为参数的东西。现在,这种机制主要用于Redux/Flux,其中整个状态存储在一个Store中,每个组件都从中获取它们的状态。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      handlerProps: {
        onClick: { count: 0},
        onChange: { count: 0}
      }
    }
  }
  
  onClickHandler = () => {
    const state = this.state.handlerProps.onClick;
    console.log('onClick', state.count);
  }
  
  onChangeHandler = (value) => {
    const state = this.state.handlerProps.onChange;
    console.log('onClick', state.count);
    this.setState({value: value})
  }
  
  buttonClick = () => {
    const random = Math.ceil(Math.random()* 10) % 2;
    const handler = ['onClick', 'onChange'][random];
    const state = this.state.handlerProps;
    state[handler].count++;
    console.log('Changing for event: ', handler);
    this.setState({handlerProps: state});
  }
  
  render () {
    return (
      <div>
        <input onClick={this.onClickHandler} onChange={this.onChangeHandler} />
        <button onClick={ this.buttonClick }>Update Props</button>
      </div>
    )
  }
}

ReactDOM.render(<MyComponent/>, document.querySelector('.content'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>
<div class='content' />

答案 3 :(得分:0)

我所知道的唯一方法是创建一个新的React组件,它将值和事件处理程序作为道具。

这样,作为函数的处理程序保持静态,并且由于该值是单独传递的(在它自己的prop中),所以不会重新实现任何函数。因为你不会绑定任何东西,也不会每次都创建一个新函数。

以下是一个例子:

我们有两个按钮。第一个打印当前状态变量value,另一个打印一个。

通常,如果我们使用onClick={() => this.print(this.state.value)}完成此操作,那么每次MyApp组件重新渲染时,我们都会获得此函数的新实例。在这种情况下,每次我们使用setState()内的this.increment增加值时,它都会重新渲染。

但是,在此示例中,没有this.print的新实例发生,因为我们只是将其引用传递给按钮。换句话说,没有脂肪箭头也没有约束力。

<Button />组件中,我们有一个<button>我们将事件处理程序传递给函数 - 就像我们在<MyApp />中所做的那样。但是,在这里我们确切地知道要传递给函数的内容。因此,我们myHandler触发this.props.handler(this.props.value)

&#13;
&#13;
class MyApp extends React.Component {
  
  constructor() {
    super();
    this.state = {
      value: 0
    };
  }
  
  print = (value) => {
    console.log(value);
  }

  increment = () => {
    // This will trigger a re-render, but none of the functions will be reinstanciated!
    this.setState((prevState) => ({value: prevState.value + 1}));
  }
 
  render() {
    // Note that both handlers below are passed just the references to functions. No "bind" and no fat arrow.
    return(
      <div>
        <Button handler={this.print} value={this.state.value}>Print</Button>
        <button onClick={this.increment}>Increment</button>
      </div>
    );
  }
}

class Button extends React.Component {
  
  // Clicking the button will trigger this function, which in turn triggers the function with the known argument - both of which were passed down via props.
  myHandler = () => this.props.handler(this.props.value);
  
  render() {
    // Note again that the handler below is just given the reference to a function. Again, not "bind" nor fat arrow.
    return(
      <button onClick={this.myHandler}>{this.props.children}</button>
    );
  }  
}
 
ReactDOM.render(<MyApp />, document.getElementById("app"));
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
&#13;
&#13;
&#13;

虽然很乏味,但它是一种有效的解决方案。话虽这么说,即使你每次渲染创建一个新函数,性能影响也很小。来自official docs

  

此语法的问题是每次LoggingButton呈现时都会创建不同的回调。在大多数情况下,这很好。