这取决于您如何获取参数。有时您无法.bind
轻松避免使用 a或箭头函数,但大多数时候您可以以某种方式获取参数。正如您在@CertainPerformance 的回答中看到的那样,如果您可以在构造函数中使用此参数,您可以更喜欢这种方式。但是可以有其他方法。
例如,假设您在该州有一个列表。.bind
您可以将列表元素传递给子组件,然后在那里使用回调处理程序,而不是直接映射此列表并在那里使用 a或箭头函数。
class App extends React.Component {
state = {
list: [ "foo", "bar" ],
};
handleClick(el) { console.log( el ) }
render() {
return (
<div>
{this.state.list.map( el => (
<Child key={el} el={el} onClick={this.handleClick} />
) )}
</div>
);
}
}
const Child = ( props ) => {
const handleClick = () => props.onClick( props.el );
return (
<div>
{props.el}
<button onClick={handleClick}>Click</button>
</div>
);
};
ReactDOM.render( <App />, document.getElementById( "root" ) );
<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="root"></div>
我正在通过演示更新我的答案,如何使用内联箭头函数,或绑定它,或使用柯里化函数会导致这里的娱乐。
假设您有一个组件,并且该组件有一个子组件,写为React.PureComponent
. 通常,如果这个孩子的props没有改变,它就不会重新渲染。凉爽的。我们在父组件中有一个类方法,并希望将其作为处理程序传递给我们的子组件。让我们看看这里发生了什么。
首先,我不传递处理程序,当您增加父组件中的计数器时,子组件不会再次重新渲染(初始渲染除外)。这是因为我们将其定义为PureComponent
. 我们不希望它被重新渲染,除非它的 props 改变。
class App extends React.Component {
state = {
counter: 0,
};
increment = () =>
this.setState( currentState => ( {
counter: currentState.counter + 1,
} ) );
handleClick(param) { console.log( param ) }
render() {
return (
<div>
<button onClick={this.increment}>Increment</button>
Counter is: {this.state.counter}
<Child />
</div>
);
}
}
class Child extends React.PureComponent {
render() {
console.log( "child rendered" );
return (
<div>
<button onClick={this.props.onClick}>Click</button>
</div>
);
}
}
ReactDOM.render( <App />, document.getElementById( "root" ) );
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
如您所见,子组件没有重新渲染。现在让我们用我们的类方法来做到这一点,使用内联箭头函数。
class App extends React.Component {
state = {
counter: 0,
};
increment = () =>
this.setState( currentState => ( {
counter: currentState.counter + 1,
} ) );
handleClick( param ) { console.log( param ) }
render() {
return (
<div>
<button onClick={this.increment}>Increment</button>
Counter is: {this.state.counter}
<Child onClick={() => this.handleClick( "some param" )} />
</div>
);
}
}
class Child extends React.PureComponent {
render() {
console.log( "child rendered" );
return (
<div>
<button onClick={this.props.onClick}>Click</button>
</div>
);
}
}
ReactDOM.render( <App />, document.getElementById( "root" ) );
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
oop,当我们增加计数器时,就会呈现孩子。但是,它与计数器状态没有任何关系,我们不想要这个。那么为什么要重新渲染呢?这是因为我们在onClick
它获得的props中使用了内联箭头函数。由于此函数在父级的每次渲染中重新创建,因此它的引用更改为不同的函数,子级认为它获得了一个新的props!但实际上它并没有得到它。我们可以将参数与我们的处理程序一起使用,但有不必要的渲染。
现在随着.bind
. 我不在this
绑定中使用,因为我们不在this
我们的简单方法中使用。它只是记录一个参数。
class App extends React.Component {
state = {
counter: 0,
};
increment = () =>
this.setState( currentState => ( {
counter: currentState.counter + 1,
} ) );
handleClick( param ) { console.log( param ) }
render() {
return (
<div>
<button onClick={this.increment}>Increment</button>
Counter is: {this.state.counter}
<Child onClick={this.handleClick.bind( null, "some param" )} />
</div>
);
}
}
class Child extends React.PureComponent {
render() {
console.log( "child rendered" );
return (
<div>
<button onClick={this.props.onClick}>Click</button>
</div>
);
}
}
ReactDOM.render( <App />, document.getElementById( "root" ) );
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
同样在这里,我们可以使用参数,但没有不必要的渲染。现在有一个咖喱函数。
class App extends React.Component {
state = {
counter: 0,
};
increment = () =>
this.setState( currentState => ( {
counter: currentState.counter + 1,
} ) );
handleClick( param ) {
return function() {
console.log( param )
}
}
render() {
return (
<div>
<button onClick={this.increment}>Increment</button>
Counter is: {this.state.counter}
<Child onClick={this.handleClick( "some param" )} />
</div>
);
}
}
class Child extends React.PureComponent {
render() {
console.log( "child rendered" );
return (
<div>
<button onClick={this.props.onClick}>Click</button>
</div>
);
}
}
ReactDOM.render( <App />, document.getElementById( "root" ) );
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
惊喜!再次不必要的渲染。现在,对于一个组件,这不是那么重要。但是如果你的应用程序有数百个像这个孩子这样的组件怎么办?
现在,让我们假设我以某种方式获得了参数。我在这里用硬编码字符串模仿它。
class App extends React.Component {
state = {
counter: 0,
};
increment = () =>
this.setState( currentState => ( {
counter: currentState.counter + 1,
} ) );
handleClick() { console.log( "some param" ) }
render() {
return (
<div>
<button onClick={this.increment}>Increment</button>
Counter is: {this.state.counter}
<Child onClick={this.handleClick} />
</div>
);
}
}
class Child extends React.PureComponent {
render() {
console.log( "child rendered" );
return (
<div>
<button onClick={this.props.onClick}>Click</button>
</div>
);
}
}
ReactDOM.render( <App />, document.getElementById( "root" ) );
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
呸!由于我们使用了函数引用,因此没有按预期进行不必要的重新渲染。我可以使用参数,但生活并不那么容易,OP 实际上询问我们如何在不使用内联箭头函数、绑定或柯里化函数的情况下使用参数。所有的大惊小怪都是关于这个的。
即使我们没有将此处理程序向下传递给组件,但正如我们在此处看到的那样,它仍会在父级的每个渲染中重新创建。如果您有一个项目列表,假设有 500 个,并且您将它们映射到父组件中的按钮并在这里使用箭头功能等,这意味着它们将在每次渲染中重新创建(500 次)!
所以,没有任何简单的方法可以做到这一点。如果我们的参数不是来自事件对象,那么我们要么使用@CertainPerformance 的解决方案,要么尝试像我在这里所做的那样更改我们的逻辑。