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

update to use new React context #51

Closed
francescocretti opened this issue Feb 16, 2022 · 6 comments
Closed

update to use new React context #51

francescocretti opened this issue Feb 16, 2022 · 6 comments
Assignees

Comments

@francescocretti
Copy link

Hi everyone. Thanks for developing and maintaining this package.

I'm encountering a strange error when trying to use d3plus-react in a Next.js project.
In particular I'm trying to use the GeoMap component.

Expected Behavior

Install d3plus-react, import GeoMap in custom component and use with custom data.

Current Behavior

The mere fact of importing the GeoMap throws a build-time error: SyntaxError: Unexpected token 'export'.

Steps to Reproduce (for bugs)

  1. setup a Next.js v12 project
  2. install d3plus-react
  3. create a new component and import GeoMap from d3plus-react

Attachments

Here's a screenshot of the error

Schermata del 2022-02-16 11-15-23

Here's my component's code

import { useEffect, useState } from "react";

import { Geomap } from "d3plus-react";

import { getJSON } from "../utils";

const PointMap = ({ dataApiUrl }) => {

  const [data, setData] = useState(null);

  useEffect(() => {
    getJSON(dataApiUrl)
      .then(res => setData(res))
      .catch(console.error);
  }, []);

  return (
    data &&
    <Geomap
      className="pointmap"
      config={{
        zoom: true,
        ocean: '#fff',
        legend: false,
        data: data,
        groupBy: 'city',
        label: d => d.city,
        point: d => [d.longitude, d.latitude],
        pointSize: d => d.value,
        pointSizeMin: 1,
        projection: 'geoMercator',
        tiles: true,
        tilesUrl: 'https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}@2x.png',
        attribution: false
      }}
    />
  );
};

export default PointMap;

Your Environment

  • Browser Name: Chrome 98 / Firefox 97
  • Operating System and Version: Ubuntu 20.04.2 LTS
  • package versions:
"d3plus-react": "^1.1.1",
"next": "12.0.10",
"react": "17.0.2",
"react-dom": "17.0.2"

Let me know you I can provide any other information. Thanks a lot.
Francesco

@davelandry
Copy link
Member

🤔 d3plus as a library is designed to run in the browser and the package is exported in ESM format. From some initial googling, I found the following StackOverflow post which says that NextJS will only compile ESM import/exports that are present in the src/ directory, and you may need to manually add the node_modules d3plus code to your NextJS loader config: https://stackoverflow.com/questions/65936222/next-js-syntaxerror-unexpected-token-export

@davelandry davelandry self-assigned this Feb 16, 2022
@francescocretti
Copy link
Author

Ehy @davelandry, thanks for the hint, I'll take a look at it.

Meanwhile, as a temporary workaround, I managed to make it work copying the Viz.js and Geomap.js wrappers (as they are) into my project folder, installing the Geomap component directly from the d3plus-geomap package and importing it in my component, instead of using the one in node_modules.

Now I've got React complaining about the usage of Legacy context API in the Viz.js component, but that's a whole different story :)

Hope I made myself clear, I'll post news ASAP

@francescocretti
Copy link
Author

UPDATE

I tried to use next-transpile-modules to load d3plus-react into my Next.js project (as one of the answers in the Stackoverflow posted by @davelandry suggested) and it works.

So just npm i next-transpile-modules and change the next.config.js file like this:

const withTM = require('next-transpile-modules')(['d3plus-react']);

module.exports = withTM({
  reactStrictMode: true
});

It works properly but I still get the Legacy context API warning from React. This makes sense because this module does exactly what I did manually and described in my previous post.

This is the warning:

Warning: Legacy context API has been detected within a strict-mode tree.
The old API will be supported in all 16.x releases, but applications using it should migrate to the new version.

So I decided to stick with my solution and replace the legacy context with the new React Context API, so I've got a correct module load and no annoying React warning.

@davelandry don't know if that's something that may be of interest to you, I just created and exported a context from Viz.js using the new syntax.

export const D3PlusContext = React.createContext({
  d3plus: {}
});

class Viz extends Component {
  static contextType = D3PlusContext;
  
  // ... everything as it was before
}

// removed this
// Viz.contextTypes = {
//   d3plus: PropTypes.object
// };

An example of usage:

import { D3PlusContext } from '../d3plus-wrapper';
/*
 * this is where I put the wrapper, I guess the best solution would be to export it from `index.js`
 * so you can just do - import { D3PlusContext } from 'd3plus-react' -
 */
 
// example of comfiguration I took from your README
const d3plusConfig = {
  shapeConfig: {
    fontFamily: "Comic Sans MS"
  }
};

const MyApp = () => {
  return (
    <D3PlusContext.Provider value={{ d3plus: d3plusConfig }}>
      <main>
        {/* child components containing visualizations */}
      </main>
    </D3PlusContext.Provider>
  );
};

export default MyApp;

Thank you for your time

@davelandry davelandry changed the title Usage with Next.js 12 throws unhandled error update to use new React context Feb 16, 2022
@davelandry davelandry removed their assignment Feb 16, 2022
@alexandersimoes
Copy link

@francescocretti I also ran into the same problem using d3plus + next.js. My solution has to wrap the d3plus component I was importing with a dynamic import like the following:

import dynamic from "next/dynamic";
const TreemapCountries = dynamic(
  () => import("../../components/treemapCountries"),
  {
    ssr: false,
  }
);

My treemapCountries component then imports the required d3plus module normally.

import { Treemap } from "d3plus-react";

export default function TreemapCountries() {
  return (
    <>
      <Treemap
        config={{
          data,
           ...
        }}
      />
    </>
  );
}

@francescocretti
Copy link
Author

Thanks @alexandersimoes for the alternative!

@davelandry
Copy link
Member

With version v1.2 of the library, we have upgraded the codebase to use proper imports/exports and are now exporting a Context/Provider to use when passing down global configs: https://github.com/d3plus/d3plus-react/releases/tag/v1.2.0

@davelandry davelandry self-assigned this Dec 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants