每次鼠标悬停时重新绘制自定义标签渲染图
Recharts custom label render every time when mouse over
我为饼图创建自定义标签
CustomLabel.js
const renderCustomizedLabel = (props,centerText) => {
console.log("rendered")
return (
<g>...</g>
);
};
export default renderCustomizedLabel;
CustomPieChart.js
export default class Example extends PureComponent {
constructor(props){
super(props);
}
render() {
return (
<ResponsiveContainer width="100%" aspect={2}>
<PieChart width={600} height={600}>
<Pie
data={this.props.data}
dataKey="value"
nameKey="name"
cx="50%" cy="50%" innerRadius={80} outerRadius={90}
label={(a)=>CustomPieChartLabel(a,this.props.centerText)}>
{this.props.data.map((entry, index) => (<Cell key={`cell-${index}`} fill={entry.color} />))}
</Pie>
</PieChart>
</ResponsiveContainer>
);
}
}
问题
每次将鼠标悬停在单元格上时,renderCustomizedLabel 都会工作并呈现每个数据。
在上面的代码中,我没有使用任何 onMouseMove、onMouseOver、onMouseEnter 方法。
如上图,当鼠标悬停在红色、蓝色或灰色区域时,console.log("rendered") 工作 3 次。
为了解决这个问题我尝试使用React.memo
CustomLabelWithMemo.js
const MemoComponent = React.memo(function renderCustomizedLabel(props) {
console.log("rendered")
return (
<g>...</g>
);
});
export default MemoComponent
但是它给我一个错误
TypeError: Object(...) is not a function
我该如何解决这个问题?
复制link
CodeSandBox
我认为查看沙箱的主要问题是你仍在使用 MemoComponent
就好像它是一个常规函数,而不是在将它传递给 label
prop 时的组件您的 Pie
组件。
你这样做:
label={(a) => CustomPieChartLabel(a, this.props.centerText)}
相反,您可以这样做:
label={<CustomPieChartLabel centerText={this.props.centerText} />}
我也稍微调整了你的 CustomPieChartLabel.js
文件:
import React from "react";
const RADIAN = Math.PI / 180;
const renderCustomizedLabel = (props) => {
console.log("rendered");
const {
cx,
cy,
midAngle,
outerRadius,
fill,
payload,
percent,
value,
centerText
} = props;
const sin = Math.sin(-RADIAN * midAngle);
const cos = Math.cos(-RADIAN * midAngle);
const sx = cx + (outerRadius + 10) * cos;
const sy = cy + (outerRadius + 10) * sin;
const mx = cx + (outerRadius + 30) * cos;
const my = cy + (outerRadius + 30) * sin;
const ex = mx + (cos >= 0 ? 1 : -1) * 30;
const ey = my;
const textAnchor = cos >= 0 ? "start" : "end";
return (
<g>
<text x={cx} y={cy} textAnchor="middle" fill={fill}>
{centerText.title}
</text>
<text x={cx} y={cy} dy={20} textAnchor="middle" fill={fill}>
{centerText.value}
</text>
<path
d={`M${sx},${sy}L${mx},${my}L${ex},${ey}`}
stroke={fill}
fill="none"
/>
<circle cx={ex} cy={ey} r={2} fill={fill} stroke="none" />
<text
style={{ fontWeight: "bold" }}
x={ex + (cos >= 0 ? 1 : -1) * 12}
y={ey}
textAnchor={textAnchor}
fill={fill}
>
{payload.name}
</text>
<text
x={ex + (cos >= 0 ? 1 : -1) * 12}
y={ey}
dy={18}
textAnchor={textAnchor}
fill="#999"
>
{value}
</text>
</g>
);
};
const CustomPieChartLabel = React.memo(renderCustomizedLabel);
export default CustomPieChartLabel;
我为饼图创建自定义标签
CustomLabel.js
const renderCustomizedLabel = (props,centerText) => {
console.log("rendered")
return (
<g>...</g>
);
};
export default renderCustomizedLabel;
CustomPieChart.js
export default class Example extends PureComponent {
constructor(props){
super(props);
}
render() {
return (
<ResponsiveContainer width="100%" aspect={2}>
<PieChart width={600} height={600}>
<Pie
data={this.props.data}
dataKey="value"
nameKey="name"
cx="50%" cy="50%" innerRadius={80} outerRadius={90}
label={(a)=>CustomPieChartLabel(a,this.props.centerText)}>
{this.props.data.map((entry, index) => (<Cell key={`cell-${index}`} fill={entry.color} />))}
</Pie>
</PieChart>
</ResponsiveContainer>
);
}
}
问题
每次将鼠标悬停在单元格上时,renderCustomizedLabel 都会工作并呈现每个数据。
在上面的代码中,我没有使用任何 onMouseMove、onMouseOver、onMouseEnter 方法。
如上图,当鼠标悬停在红色、蓝色或灰色区域时,console.log("rendered") 工作 3 次。
为了解决这个问题我尝试使用React.memo
CustomLabelWithMemo.js
const MemoComponent = React.memo(function renderCustomizedLabel(props) {
console.log("rendered")
return (
<g>...</g>
);
});
export default MemoComponent
但是它给我一个错误
TypeError: Object(...) is not a function
我该如何解决这个问题?
复制link CodeSandBox
我认为查看沙箱的主要问题是你仍在使用 MemoComponent
就好像它是一个常规函数,而不是在将它传递给 label
prop 时的组件您的 Pie
组件。
你这样做:
label={(a) => CustomPieChartLabel(a, this.props.centerText)}
相反,您可以这样做:
label={<CustomPieChartLabel centerText={this.props.centerText} />}
我也稍微调整了你的 CustomPieChartLabel.js
文件:
import React from "react";
const RADIAN = Math.PI / 180;
const renderCustomizedLabel = (props) => {
console.log("rendered");
const {
cx,
cy,
midAngle,
outerRadius,
fill,
payload,
percent,
value,
centerText
} = props;
const sin = Math.sin(-RADIAN * midAngle);
const cos = Math.cos(-RADIAN * midAngle);
const sx = cx + (outerRadius + 10) * cos;
const sy = cy + (outerRadius + 10) * sin;
const mx = cx + (outerRadius + 30) * cos;
const my = cy + (outerRadius + 30) * sin;
const ex = mx + (cos >= 0 ? 1 : -1) * 30;
const ey = my;
const textAnchor = cos >= 0 ? "start" : "end";
return (
<g>
<text x={cx} y={cy} textAnchor="middle" fill={fill}>
{centerText.title}
</text>
<text x={cx} y={cy} dy={20} textAnchor="middle" fill={fill}>
{centerText.value}
</text>
<path
d={`M${sx},${sy}L${mx},${my}L${ex},${ey}`}
stroke={fill}
fill="none"
/>
<circle cx={ex} cy={ey} r={2} fill={fill} stroke="none" />
<text
style={{ fontWeight: "bold" }}
x={ex + (cos >= 0 ? 1 : -1) * 12}
y={ey}
textAnchor={textAnchor}
fill={fill}
>
{payload.name}
</text>
<text
x={ex + (cos >= 0 ? 1 : -1) * 12}
y={ey}
dy={18}
textAnchor={textAnchor}
fill="#999"
>
{value}
</text>
</g>
);
};
const CustomPieChartLabel = React.memo(renderCustomizedLabel);
export default CustomPieChartLabel;