10000 ResponsiveLine is mutating dates in the 'data' prop. · Issue #2770 · plouc/nivo · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

ResponsiveLine is mutating dates in the 'data' prop. #2770

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
bayview opened this issue May 30, 2025 · 3 comments
Open

ResponsiveLine is mutating dates in the 'data' prop. #2770

bayview opened this issue May 30, 2025 · 3 comments
Labels
🪲 bug 📈 line @nivo/line package

Comments

@bayview
Copy link
bayview commented May 30, 2025

Using the ResponsiveLine component, I send x values that are Date objects. After the chart is drawn, some of my Date objects have been changed. Specifically, the first and last data item in the first series have been changed from midnight UTC to midnight in the local time zone.

I tried to make a codesandbox.io but could not get the site to work for me.
I created this reproducible example, as simple as possible. Here's the App.tsx:

import React, { useEffect } from 'react';
import ReactDOM from 'react-dom/client';
import { ResponsiveLine } from '@nivo/line';

const App: React.FC = () => {

    const chartData = [
        {
            id: 'id',
            data: [
                { x: new Date('2023-01-01T00:00:00Z'), y: 120 },
                { x: new Date('2023-01-02T00:00:00Z'), y: 150 },
                { x: new Date('2023-01-03T00:00:00Z'), y: 130 },
                { x: new Date('2023-01-04T00:00:00Z'), y: 180 },
            ],
        },
    ];

    // Helper function for consistent logging of Date object's internal state
    const logDateStates = (prefix: string) => {
        chartData[0].data.forEach((point, index) => {
            // Check if the UTC time components are all zeros (i.e., exactly UTC midnight)
            const isMidnightUTC =
                point.x.getUTCHours() === 0 &&
                point.x.getUTCMinutes() === 0 &&
                point.x.getUTCSeconds() === 0 &&
                point.x.getUTCMilliseconds() === 0;

            // Define the style for the console log
            const colorStyle = isMidnightUTC ? '' : 'color: red; font-weight: bold;';

            console.log(`${prefix} Point ${index}:`);
            // Apply the style to the ISO String and getTime() logs
            console.log(`%c  ISO String (internal): ${point.x.toISOString()}`, colorStyle);
            console.log(`%c  getTime() (milliseconds UTC epoch): ${point.x.getTime()}`, colorStyle);
        });
    };

    // Log immediately when the component function is called (before render)
    console.log('--- LOGS: BEFORE RENDER ---');
    logDateStates('BEFORE RENDER');

    // Log after the component has initially rendered
    useEffect(() => {
        console.log('--- LOGS: AFTER INITIAL RENDER ---');
        logDateStates('AFTER INITIAL RENDER');
    }, []); // Empty dependency array ensures this runs only once after mount

    // Log on button click (to check state after Nivo has potentially mutated)
    const handleLogChartData = () => {
        console.log('--- LOGS: ON BUTTON CLICK ---');
        logDateStates('ON BUTTON CLICK');
    };

    return (
        <div style={{ padding: '20px', maxWidth: '900px', margin: '0 auto' }}>
            <div style={{ height: '400px', width: '100%' }}>
                <ResponsiveLine
                    data={chartData}
                    xScale={{
                        type: 'time',
                        format: 'native',
                        precision: 'day',
                    }}
                />
            </div>

            <button
                onClick={handleLogChartData}
                style={{
                    marginTop: '20px',
                    padding: '10px 20px',
                    backgroundColor: '#007bff',
                    color: 'white',
                    border: 'none',
                    borderRadius: '5px',
                    cursor: 'pointer',
                    fontSize: '16px'
                }}
            >
                Log chartData State Now
            </button>

            {/* Explanatory text for the bug report */}
            <p style={{ marginTop: '20px', fontSize: '0.9em', lineHeight: '1.4em' }}>
                Something about <code>ResponsiveLine</code> is mutating the dates in the <code>data</code> prop.
                <br />
                This is the shortest reproducible version I could create. The dates are created as midnight UTC.
                <br />
                The dates and times remain okay on component load and are fine after the first 'render', but if you click
                the "Log chartData State Now" button after drawing is complete, you will see that the first and the last data item in the series
                have changed their internal UTC times. They should not change. Adding <code>xScale.useUTC: true</code> does not prevent this.
            </p>
        </div>
    );
};

// Render the App component into the DOM
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
    <React.StrictMode>
        <App />
    </React.StrictMode>
);

export default App;

Desktop
OS: Ubuntu 24.04.02 LTS
Browser: Firefox 139.0 and Chromium 136.0.7103.113

@plouc plouc added 🪲 bug 📈 line @nivo/line package labels May 31, 2025
@plouc
Copy link
Owner
plouc commented May 31, 2025

Here is a codesandbox for this: https://codesandbox.io/p/devbox/nivo-line-react-19-forked-ng2wjz?workspaceId=ws_Wbxoz5kWYrbECfDsUZGqpu, also, it's best to define chartData outside of the component (or to memoize it), otherwise a change in the App state will generate different dates. That said, even if I extract or memoize chartData, I still get different results.

@plouc
Copy link
Owner
plouc commented May 31, 2025

btw, thank you for the detailed report, even if you didn't provide something I could immediately run, it was straightforward to reproduce (however, it's best to mention the version you're using).

@bayview
Copy link
Author
bayview commented May 31, 2025

Thanks for taking a look. Too late now, but I'm running v0.99.0 :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🪲 bug 📈 line @nivo/line package
Projects
None yet
Development

No branches or pull requests

2 participants
0