recharts / react-smooth

react animation
MIT License
277 stars 38 forks source link

Causes chart to prematurely stop rendering #44

Open avindra opened 3 years ago

avindra commented 3 years ago

There are some indications from users that Animations from react-smooth are causing the graph to render partially / in an incomplete state. Users have been using isAnimationActive={false} to disable animations to workaround the bug. See recharts issues:

https://github.com/recharts/recharts/issues/1426 https://github.com/recharts/recharts/issues/1821

incraigulous commented 2 years ago

The issue seems to be related to the frequency in which your parent component needs to rerender, or possibly how often your data array reference changes. The workaround seems to be to do two things:

I set a unique key on the Chart or ResponsiveContainer that forces the chart to rerender when the parent component rerenders. This can lead to issues with your chart reanimating on each rerender, which may not be your desired effect. Here is how I worked that out. Note that I'm turning off animations after a timeout to prevent duplicate animations after the key change. You would think that I could simply turn the animation off at onAnimationEnd but that callback seems to be called before the animation actually ends for some reason. It's also possible that your component will never actually finish the animation if this bug does happen to occur during the animation. I had better luck with the following approach:

const RingChart = ({data, colors, angle = 140}) => {
    let [animate, setAnimate] = useState(true)
    const onAnimationStart = useCallback(() => {
        setTimeout(() => {
            setAnimate(false)
        }, 2000)
    }, [])

    return (<div>
            <div  ref={ref} className={"absolute w-grid-7 h-grid-1 l-grid-7 t-grid-7"}/>
            <ResponsiveContainer key={uniqid()}>
                <PieChart>
                    <Pie
                        isAnimationActive={animate}
                        data={data}
                        startAngle={angle}
                        endAngle={angle + 360}
                        cx={'50%'}
                        cy={'50%'}
                        outerRadius={'70%'}
                        innerRadius={'47%'}
                        fill="#8884d8"
                        dataKey="value"
                        paddingAngle={0}
                        labelLine={<LabelLine/>}
                        label={<Label/>}
                        onAnimationStart={onAnimationStart}
                    >
                        {data.map((entry, index) => (
                            <Cell key={`cell-${index}`} fill={colors[index % colors.length]} stroke="none"/>
                        ))}
                    </Pie>
                </PieChart>
            </ResponsiveContainer>
        </div>
    )
}
nightwolf-041 commented 2 years ago

any updates ?

pl12133 commented 2 years ago

It's worth noting that when the Animate component unmounts, it does not call onAnimationEnd. This makes it impossible for recharts to clean up any outstanding animations when Animate unmounts.

Perhaps there could be an onAnimationStopped prop to address cases where the AnimateManager is stopped abruptly.

semoal commented 2 years ago

We would love a contribution from your side @pl12133 , calling the onAnimationEnd on unmount

ckifer commented 1 year ago

Merged https://github.com/recharts/react-smooth/pull/80 which calls onAnimationEnd on unmount - this should solve part of this