我的问题是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)}/>
}
没有更好,因为它仍然在创造一个新功能。
所以我的问题是,我如何创建一个函数,我可以在不创建新组件的情况下将参数传递给它,并且不在每个渲染上绑定新的函数?
答案 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)
。
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;
虽然很乏味,但它是一种有效的解决方案。话虽这么说,即使你每次渲染做创建一个新函数,性能影响也很小。来自official docs:
此语法的问题是每次
LoggingButton
呈现时都会创建不同的回调。在大多数情况下,这很好。