NextJS issue with server side rendering with react-d3-tree - reactjs

To start off, I have looked at issue number 40 and 95 on the react-d3-tree github
I don't see anything on StackOverflow that would help me. I am trying to implement the parseJSON method so I can take my own JSON file from the project folder and then generate a tree diagram.
Let's start from what I did in the beginning. I copy pasted the example code which worked for 2 seconds before crashing. Reason? Server Side Rendering. Great, so then I find this from NextJS which allows me to disable SSR for some components. Hey, now the example code is working. Let's try the example code where they use external data! Nope, it can't find the parseJSON method. I have no idea what to do, can't find anything to fix this. I am trying to import this function that has some issue with SSR, but because it isn't a component I am not able to import it using dynamic, and I can't import normally because it causes a "window is not defined" error because of SSR.
The following are my main two files.
DynamicComponent.js [Version 1]
import dynamic from 'next/dynamic';
const Tree = dynamic(
() => import('react-d3-tree'),
{ ssr: false },
);
export default Tree;
DynamicComponent.js [Version 2]
import dynamic from 'next/dynamic';
export const Tree = dynamic(
() => import('react-d3-tree'),
{ ssr: false },
);
export const treeUtil = dynamic(
() => import('react-d3-tree/src/util'),
{ ssr: false },
);
Diagram/index.js
import React from 'react';
import { Tree, treeUtil } from '../DynamicComponent';
const myTreeData = require('../fakeData.json');
class Diagram extends React.PureComponent {
constructor() {
super();
this.state = {
data: undefined,
};
}
componentWillMount() {
treeUtil.parseJSON(myTreeData)
.then((data) => {
this.setState({ data });
});
}
render() {
return (
<div
id="treeWrapper"
style={{ width: '50em', height: '20em' }}
>
<Tree data={this.state.data} />
</div>
);
}
}
export default Diagram;
Error I Get with Version 1
ReferenceError: treeUtil is not defined
Error I Get with Version 2
TypeError: _DynamicComponent__WEBPACK_IMPORTED_MODULE_1__.treeUtil.parseJSON is not a function
Please StackOverflow, you're my only hope.

I ran into the same problem with Cytoscape, a similar library (but specifically for graph-network visualization). It took lots of trial and error, but the solution was:
import the component dynamically
remove the import JSON and inline it into a js file. For some stupid reason, that worked for me and was the magic fix. (how big was your JSON file?) Worse-case try copying & pasting into the component itself.
For your component try this:
// convert fakeData.json to fakeData.js
export default {...fake data here };
import React from 'react';
import dynamic from 'next/dynamic'
import myTreeData from 'fakeData';
const Tree = dynamic(
() => import('./dynamicComponent'),
{ ssr: false }
);
// you can also delineate a loading component;
// converted to hooks for '21
const Diagram = () => {
const [data,setData] = useState({});
useEffect(() => {
treeUtil.parseJSON(myTreeData)
.then((data) => {
setData(data);
})
},[treeUtil,myTreeData,setData]);
return (
<div
id="treeWrapper"
style={{ width: '50em', height: '20em' }}
>
<Tree data={data} />
</div>
);
}
export default Diagram;

I guess treeUtil is not a react component, so you can't use dynamic to import it. Just import it normally may be work.
import dynamic from 'next/dynamic';
export const Tree = dynamic(
() => import('react-d3-tree'),
{ ssr: false },
);
export { default as treeUtil } from 'react-d3-tree/src/util';

Related

react dynamic component type example

How/Where can i add types to the dynamic component Icons[name] ?
import * as Icons from "react-icons/fa";
const DynamicFaIcon = ({ name }: any) => {
const IconComponent = Icons[name];
return <IconComponent />;
};
You could just grap the keys from the import, since its a JS object like any other:
import * as Icons from "react-icons/fa";
const DynamicFaIcon = ({ name }: {name: keyof typeof Icons}) => {
const IconComponent = Icons[name];
return <IconComponent />;
};
I would be careful about importing literally everything from that package though. There's over 1,500 components in there, does any application actually make use of all of them? You'll end up bundling way more than you need.
This is my answer on dynamic icons problem, is it your question answer ?? , maybe it will help you, use it like this `
import React from 'react';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import {library} from '#fortawesome/fontawesome-svg-core';
import * as Icons from '#fortawesome/free-solid-svg-icons';
const iconList = Object.keys(Icons)
.filter((key) => key !== 'fas' && key !== 'prefix')
.map((icon) => Icons[icon]);
library.add(...iconList);
const Feature = ({ carFeature }) => {
console.log(carFeature);
return (
<div>
<FontAwesomeIcon icon={carFeature?.icon} color="#ddd" />
<h3>{carFeature?.name}</h3>
<p>{carFeature?.desc}</p>
</div>
);
};
export default Feature;
If no then try this
Not the OP's direct issue but for users encountering this error for libraries not under their control, one can suppress this error is by adding:
{
...
"suppressImplicitAnyIndexErrors": true,
...
}
to the tsconfig.json file.
Read more here Question Answer

React real-time chart with react.context and socket.io

I'm trying to build a website for displaying real-time charts in typescript with react for my learning. But I can not get values from a server properly before displaying the chart.
What I want to do is ...
Communication protocol is websocket using socket.io.
Using socket.io and storing data are inside React.Context(useSocket.tsx) so as to access the data from any react components easily.
Displaying the data is in Home.tsx.
The socket events are initial_data and new_data.
The initial_data event is received at the time the accessing the website at first.
The new_data event is received at regularly.
The time getting both events above, update values inside Home.tsx automatically.
I researched some articles on the web, for example, explaining a way that using socket.io inside a useEffect() function that returning socket.disconnect().
So, the code I built is below.
useSocket.tsx
import {useContext, createContext, useState, useEffect} from "react";
import {io, Socket} from "socket.io-client";
import {chartDataType} from "../types/chartDataType";
type Context = {
chartData: Array<chartDataType>;
}
const SocketContext = createContext<Context>({
chartData: [],
});
const SocketsProvider = (props: any) => {
const [chartData, setChartData] = useState();
useEffect( () => {
const socket: Socket = io("http://***.***.***.***");
socket.on('initial_data', (data) => {
console.log(data);
setChartData(data);
});
socket.on('new_data', (data) => {
console.log(data);
});
return () => { socket.disconnect() };
},[]);
return (
<SocketContext.Provider value={{chartData}} {...props} />
);
}
const useSocket = () => useContext(SocketContext);
export { SocketsProvider, useSocket };
Home.tsx
import {memo, VFC} from "react";
import { useSocket } from "../../context/useSocket";
import {Heading} from "#chakra-ui/react";
export const Home: VFC = memo(() => {
const { chartData } = useSocket();
return (
<>
<Heading as="h1">{`${chartData}`}</Heading>
</>
)
})
The above code caused an error Uncaught TypeError: Cannot read properties of undefined (reading '0') occurred in the browser console. But when the comment out the <Heading>...</Heading> line in Home.tsx, the console.log in useSocket.tsx can display the value from the server in the browser console.
I can not come up with the idea for the correct implementation. Is the definition of the type of the chartData wrong? or other reasons? The definition of the chartDataType has nothing wrong.
What is the way for the correct implementation?
What's happening is you are trying to render an empty array, the data hasn't loaded yet.
You need to check if charData exists, or if it's undefined first.
Like this:
return (
{CharData ? <Heading /> ... : null }
)

Warning: Prop `id` did not match in tradingview widget

I am trying to use TradingViewWidget in react to show charts but the chart is showing sometimes and sometimes not. Getting this Warning in console
Warning: Prop id did not match. Server: "tradingview-widget-0.7679528527764021" Client: "tradingview-widget-0.3972755056284276"
and this is my code -
import TradingViewWidget from 'react-tradingview-widget';
import { Segment } from 'semantic-ui-react';
const TechnicalChart = () => {
return (
<Segment basic >
<TradingViewWidget symbol="OANDA:USDTHB"/>
</Segment>
);
};
export default TechnicalChart;
What am I doing wrong here?
maybe you are using some sort of server side rendering, I was getting this error in Nextjs, and that was because of SSR, and I did sth like this:
const TvChart = dynamic(() => import("TvChart"), { ssr: false });
and then used it as:
<TvChart/>
and this is the chart component:
import TradingViewWidget from "react-tradingview-widget";
const TvChart = () => {
return <TradingViewWidget symbol="NASDAQ:AAPL" />;
};
export default TvChart;
and now it works well.

Can you deconstruct lazily loaded React components?

Using es6 imports, you can do this:
import { MyComponent } from "../path/to/components.js";
export default function () {
return <MyComponent/>;
}
Can I do it with React.lazy too?
const { MyComponent } = lazy(() => import("../path/to/components.js"));
I get the following error, but I'm not sure if it's related to this or some other bug I have:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined
Here is how I did it when I faced this problem with FontAwesome:
const FontAwesomeIcon = React.lazy(()=> import('#fortawesome/react-fontawesome').then(module=>({default:module.FontAwesomeIcon})))
You can if you use react-lazily.
import { lazily } from 'react-lazily';
const { MyComponent } = lazily(() => import("../path/to/components.js"));
It also allows importing more than one component:
const { MyComponent, MyOtherComponent, SomeOtherComponent } = lazily(
() => import("../path/to/components.js")
);
See this answer for more options.
React.lazy currently only supports default exports. If the module you want to import uses named exports, you can create an intermediate module that reexports it as the default. This ensures that tree shaking keeps working and that you don’t pull in unused components.
// ManyComponents.js
export const MyComponent = /* ... */;
export const MyUnusedComponent = /* ... */;
// MyComponent.js
export { MyComponent as default } from "./ManyComponents.js";
// MyApp.js
import React, { lazy } from 'react';
const MyComponent = lazy(() => import("./MyComponent.js"));
More info:
https://reactjs.org/docs/code-splitting.html#named-exports
Of course you can. It's an honest mistake many has made,
const sub = a
const obj = { a: 'alpha', b: 'beta' }
obj.sub // wrong (accessing a direct key)
obj[sub] // right (computed property)
the same mistake slipped through for many. This is a work in progress but worked like a charm, and thanks for all the other answers to tailor it to my need.
const ComponentFactory = ({ componentName, ...props }) => {
const Component = lazy(() => import('baseui/typography').then((module) => ({ default: module[componentName] })))
return (
<Suspense fallback={<div>Loading...</div>}>
<Component {...props} />
</Suspense>
)
}
usage:
<ComponentFactory
componentName='Paragraph1'
margin='0.1rem 0rem 0.25rem 0.3rem'
color={style[of].headingText}
>
{headingMessage}
</ComponentFactory>
You can't with React.lazy :
React.lazy takes a function that must call a dynamic import(). This must return a Promise which resolves to a module with a default export containing a React component.
(cf. https://reactjs.org/docs/code-splitting.html#reactlazy)
A workaround for that exists: creating an intermediate module that imports your named export and exports it as default (cf. https://reactjs.org/docs/code-splitting.html#named-exports)
I'd like to another workaround. This compotent chains the promise and adds the named export to the default export. src. Although, I'm not sure if this breaks tree shaking. There's a bit of an explanation here.
import {lazy} from 'react'
export default (resolver, name = 'default') => {
return lazy(async () => {
const resolved = await resolver()
return {default: resolved[name]}
})
}
You can resolve a promise along with the lazy loading and this way resolve your named export.
The syntax is a bit funky, but it is working:
const MyComponent = React.lazy(
() =>
new Promise(async (resolve) => {
const module = await import('../path/to/components.js');
resolve({ ...module, default: module.default });
}),
);

I am getting this error while making a small app using react can someone help me this

I am new to react I am making a small app using reactjs when I added this file and run the code it is giving this error no syntactical error are shown.
this is the code which I have written.
import React from { react }
import Card from "./Card"
const CardList = ({ robots }) => {
//const cardComponent=robots.map((user,i)=>{
return (
// key prop should have something that should not be changed
<div>
{
robots.map((user, i) => {
<Card
key={i}
id={robots[i].id}
name={robots[i].name}
email={robots[i].email} />
})
}
</div>
)
}
export default CardList
the app should run smooth.thsi is the error I am getting
What I understand is. Your import is not right. If there is another please add code for more info
import React from 'react';//not what you import
import Card from "./Card";
const CardList = ({ robots }) => { //const cardComponent=robots.map((user,i)=>{ return ( // key prop should have something that should not be changed { robots.map((user, i) => { }) } ) }

Resources