【发布时间】:2018-12-02 15:07:15
【问题描述】:
我有一个 PureComponent 渲染另一个组件并实现其onClick 回调:
class ColorPicker extends React.PureComponent {
render() {
console.log('ColorPicker being rendered');
const fields = this.props.colors.map((color, idx) => {
const fieldProps = {
key: `${idx}`,
color,
/*onClick: () => { // PROBLEM HERE
this.props.colorPicked(color);
}*/
};
return <ColorField { ...fieldProps}/>;
});
return (
<div className="bla-picker">
<div>{`Refresh seed: ${this.props.seed}`}</div>
{fields}
< /div>
);
}
}
这个组件有一个小问题:每当重新渲染ColorPicker 时,嵌套的ColorFields 也需要重新渲染,因为它们的onClick 属性每次都会更改。每当渲染组件时,使用 lambda 函数将创建该函数的新实例。
我通常通过将onClick 的实现移到render 方法之外来解决这个问题,例如:onClick: this.handleClick。但是,我这里不能这样做,因为onClick 处理程序需要捕获color 变量。
解决此类问题的最佳做法是什么?
这里有一个jsfiddle 试试看;作为一个 sn-p:
class ColorField extends React.PureComponent {
render() {
console.log('ColorField being rendered');
const divProps = {
className: 'bla-field',
style: {
backgroundColor: this.props.color
},
onClick: this.props.onClick
};
return <div { ...divProps}/>;
}
}
class ColorPicker extends React.PureComponent {
render() {
console.log('ColorPicker being rendered');
const fields = this.props.colors.map((color, idx) => {
const fieldProps = {
key: `${idx}`,
color,
/*onClick: () => { // PROBLEM HERE
this.props.colorPicked(color);
}*/
};
return <ColorField { ...fieldProps}/>;
});
return (
<div className="bla-picker">
<div>{`Refresh seed: ${this.props.seed}`}</div>
{fields}
< /div>
);
}
}
class Layout extends React.PureComponent {
constructor(props, ctx) {
super(props, ctx);
this.state = {
seed: 1
};
}
render() {
const pickerProps = {
colors: ['#f00', '#0f0', '#00f'],
colorPicked: (color) => {
console.log(`Color picked: ${color}`);
},
seed: this.state.seed
};
return (
<div>
<div
className="bla-button"
onClick = {this.btnClicked}
>
{'Click Me'}
</div>
<ColorPicker { ...pickerProps} />
</div>
);
}
btnClicked = () => {
this.setState({ seed: this.state.seed + 1 });
};
};
ReactDOM.render( <
Layout / > ,
document.getElementById("react")
);
.bla-button {
background-color: #aaa;
padding: 8px;
margin-bottom: 8px;
}
.bla-picker {}
.bla-field {
width: 32px;
height: 32px;
}
<div id="react">
</div>
<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>
只要onClick 仍然被注释掉,只有ColorPicker 会在种子更改时重新渲染(参见console.log 的输出)。只要输入onClick,所有ColorFields 也会重新渲染。
【问题讨论】:
-
对于活生生的例子(正如我上次你问这个问题时提到的那样),请使用 Stack Snippets(
[<>]工具栏按钮),而不是像 jsFiddle 这样的场外资源。 Stack Snippets 支持 React,包括 JSX; here's how to do one. -
这不是同一个问题,因为现在我使用 PureComponent 而不是 SFC。我知道 stackoverflow 允许实时示例,但是,我发现尝试一些东西很乏味;你不能,除非你按下接听按钮。
-
您觉得它乏味是没有理由将现场示例隐藏在场外。如果您认为小提琴也有用,请也包含它,而不是代替。 SO 的工作方式,您的整个问题(包括任何必要的代码)必须in 您的问题,而不仅仅是链接。两个原因:人们不应该去场外帮助你;并且链接腐烂(而且 jsFiddle 已经出现故障——事实上,就在上周遇到了麻烦),使得问题及其答案对未来的人们毫无用处。
标签: javascript reactjs lambda closures