Skip to content
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

Suspense showes warning when using ResponsiveContainer #2736

Open
1 task
wuifdesign opened this issue Dec 14, 2021 · 7 comments
Open
1 task

Suspense showes warning when using ResponsiveContainer #2736

wuifdesign opened this issue Dec 14, 2021 · 7 comments
Labels
3.0 Issues we need fixed before releasing 3.0

Comments

@wuifdesign
Copy link

  • I have searched the issues of this repository and believe that this is not a duplicate.

Same issue as #1686, but can't reopen it and it was closed without help.

Reproduction link

Edit on CodeSandbox

Steps to reproduce

Using a ResponsiveContainer inside a Suspense and lazy load an element to trigger Suspense.

What is expected?

Warning should not be logged.

What is actually happening?

Suspense will trigger following warning when the Suspense is triggered by lazy loading an element inside of it:

The width(0) and height(0) of chart should be greater than 0, please check the style of container, or the props width(100%) and height(50%), or add a minWidth(undefined) or minHeight(undefined) or use aspect(undefined) to control the height and width.
Environment Info
Recharts v2.1.8
React 17.0.2
System Windows
Browser Chrome 96.0.4664.110

Code Example:

// Test.js
import React from "react";

const Test = () => {
  return <>test</>;
};

export default Test;
// App.js
import React, { Suspense, useState, useEffect } from "react";
import { ResponsiveContainer, PieChart, Pie } from "recharts";

const Test = React.lazy(() => import("./Test"));

function App() {
  const [test, setTest] = useState(false);

  useEffect(() => {
    setTimeout(() => {
      setTest(true);
    }, 3000);
  }, []);

  return (
    <div style={{ height: 600, width: "100%" }}>
      <Suspense fallback={<div>Loading...</div>}>
        {test && <Test />}
        <ResponsiveContainer width={"100%"} height="50%">
          <PieChart>
            <Pie
              data={[
                { name: "Group A", value: 400 },
                { name: "Group B", value: 300 },
                { name: "Group C", value: 300 },
                { name: "Group D", value: 200 }
              ]}
              dataKey="value"
              cx={200}
              cy={200}
              outerRadius={60}
              fill="#8884d8"
            />
          </PieChart>
        </ResponsiveContainer>
      </Suspense>
    </div>
  );
}

export default App;
@DiegoBillares1998
Copy link

DiegoBillares1998 commented Dec 14, 2021

I fixed, you can't put height="50%" into ResponsiveContainer and width={"100%"}, the best way is put height={300}, width="100%" into ResponsiveContainer and the warning will disappear.

@wuifdesign
Copy link
Author

wuifdesign commented Dec 15, 2021

i want both values to be percent, because it should match the parent size. it works perfect this way. but if i use Suspense it shows this warning whenever a component is loaded and the chart gets hidden for a moment.

the problem is, that it somehow gets a containerWidth and containerHeight of 0 when Suspense gets triggered and this will override if both values are percentages.

      let calculatedWidth: number = isPercent(width) ? containerWidth : (width as number);
      let calculatedHeight: number = isPercent(height) ? containerHeight : (height as number);

After the Suspense is finished loading it will rerender again and looks normal. but the warning in the console is just annoying.

@semoal
Copy link
Contributor

semoal commented Dec 22, 2021

What's your suggestion?

@williamisnotdefined
Copy link

Same problem here

@williamisnotdefined
Copy link

williamisnotdefined commented Feb 9, 2022

Ok, I believe I have figured out what is happening.

When we use suspense, the "suspensed" content gets rendered in the DOM but with "display: none !important" by the react Suspense component. I strongly believe that is the reason for our warning.

There's an issue on react github (here), its related to suspense do not be showing the children (removing the "display: none" style) after the promise / request get resolved. But what is important is this comment: here. Please, take a time to understand that solution, it is not complex.

So we should render the chart only when suspense get false as value, I mean, when the promise / request get resolved.
Do I find this solution the best way? Maybe no, but it solve the warning for now.

I really would love rechart team gave some attention to this, because those warnings are really annoying when you got a lot of responsive charts in the same screen, although honestly I can't figure out a really good solution..
(Edit PS: I'm not saying that you guys don't give the properly attention to this project, far away from this. I'm glad that all of you had helped a lot of devs and you still are doing it very well! What I mean was its just a boring issue and it'll be great if it were solved - I didn't mean to be rude anyway.)

Having a look at the ResponsiveContainer component here, maybe we could check if the div ".recharts-responsive-container" is visible someway of even its parent.. Ok, really don't know, but I hope to help other people by sharing that solution that verify if the suspense fallback Loader was unmounted.

I'll let here my changes in the code:

import React, {
  useEffect,
  useState,
  Suspense as ReactSuspense,
  createContext,
  useContext,
} from 'react';

interface ISuspenseContext {
  isSuspended: boolean;
}
const SuspenseContext = createContext<ISuspenseContext>({ isSuspended: true });

/*
 * Suspense apparently renders a suspended tree before it resumes,
 * hiding it with `display: none;`.  This tweaked version lets child
 * components use the `useSuspended` hook to know if they're in a
 * rendered-while-suspended tree.
 */

interface IFallbackProps {
  children?: React.ReactElement;
  setSuspended: (boolean) => void;
}

const Fallback: React.FC<IFallbackProps> = ({ setSuspended, children }) => {
  useEffect(() => {
    return () => setSuspended(false);
  }, [setSuspended]);

  return children;
};

interface ISuspense {
  children?: React.ReactElement;
  fallback?: React.ReactElement;
}

const Suspense: React.FC<ISuspense> = ({ fallback, children }) => {
  const [suspended, setSuspended] = useState(true);

  return (
    <ReactSuspense
      fallback={<Fallback setSuspended={setSuspended}>{fallback}</Fallback>}
    >
      <SuspenseContext.Provider value={{ isSuspended: suspended }}>
        {children}
      </SuspenseContext.Provider>
    </ReactSuspense>
  );
};

Suspense.defaultProps = {
  fallback: null,
  children: null,
};

export const useSuspended = (): ISuspenseContext => {
  const context = useContext(SuspenseContext);

  if (!context) {
    throw new Error(
      'useSuspended must be used within an SuspenseContext.Provider'
    );
  }

  return context;
};

export default Suspense;

Then, when inside the component which render the ResponsiveContainer I did:

...
const { isSuspended } = useSuspended();
....
return (
  <div>
      ...
      {!isSuspended && (
         <ResponsiveContainer>
               ...........
         </ResponsiveContainer>
      )}
      ...
  </div>
)

That way my warning gone :)

But please, give me a feedback, let me know your thoughts! Probably it could be improved someway.

@rosskevin
Copy link

@williamisnotdefined is this still the method you are using? It's not working for me...specifically, in my debugging with some log statements, the <Fallback never renders (at least in storybook) so the state change never occurs. It may be noteworthy that I am currently locked on "react": "^16.8.6" until I can make some other upgrades.

@ckifer ckifer added the 3.0 Issues we need fixed before releasing 3.0 label Nov 26, 2024
@ckifer
Copy link
Member

ckifer commented Nov 26, 2024

We'll try to remove the log in 3.0. Or at least don't log it in production builds

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.0 Issues we need fixed before releasing 3.0
Projects
None yet
Development

No branches or pull requests

6 participants