Next.js component is creating multiple Lightweight Charts - next.js

I was trying to create Lightweight Charts in Next.js. Firstly, I created chart component which accepts chart data as props.
import { createChart, CrosshairMode } from 'lightweight-charts';
import { useEffect, useRef } from 'react';
const CandleStickChart = ({ OHLC_Data }) => {
const chartContainerRef = useRef(null);
useEffect(() => {
const chart = createChart(chartContainerRef.current, {
width: 700,
height: 400,
timeScale: {
timeVisible: true,
secondsVisible: false,
fixLeftEdge: true,
fixRightEdge: true,
},
crosshair: {
mode: CrosshairMode.Normal,
},
});
const candleSeries = chart.addCandlestickSeries({
priceFormat: {
type: 'price',
minMove: 0.00001,
precision: 5,
},
});
candleSeries.setData(OHLC_Data);
}, [OHLC_Data]);
return <div ref={chartContainerRef} />;
};
export default CandleStickChart;
In page component, I used getServerSideProps to fetch the data required for chart.
import { useCallback, useEffect, useState } from 'react';
import dynamic from 'next/dynamic';
import Image from 'next/image';
const CandleStickChart = dynamic(
() => import('../../components/CandleStickChart'),
{ ssr: false }
);
import { fetchTimeSeries } from '../../utils/fetchData';
const ForexPair = ({ meta, hour, day, week }) => {
const { currency_base, currency_quote, symbol, type } = meta;
const [logos, setLogos] = useState(null);
return (
<>
<CandleStickChart OHLC_Data={hour.values} />
<CandleStickChart OHLC_Data={day.values} />
<CandleStickChart OHLC_Data={week.values} />
</>
);
};
export default ForexPair;
export async function getServerSideProps(context) {
const { params, res } = context;
const { pairSymbol } = params;
res.setHeader(
'Cache-Control',
'public, s-maxage=300, stale-while-revalidate=3600'
);
const { meta, hour, day, week } = await fetchTimeSeries(
pairSymbol.replace('-', '/')
);
return {
props: {
meta,
hour,
day,
week,
},
};
}
I excluded some unnecessary codes. fetchTimeSeries function is just asynchronous function to fetch data for third party api. getServerSideProps is returning data format required in <CandleStickChart /> component.
What I expect to see is total 3 charts since I only included 3 components. but I am seeing two of each charts, total of 6 charts.
Please dont yell at me if my code looks terrible, I am new to Next.js :D. I really have no idea what is happening in my app.
p.s Charts are displaying correctly, just seeing duplicate charts for each. Thanks in advance. :D

It has to do with the way React & useEffect works under the hood.
Just add
return () => {
chart.remove();
};
after candleSeries.setData(OHLC_Data); and you won't see duplications :)

Related

How to fix this.TD[this.j5] is null using Flexmonster

I work on local environment and I use Next like framework. I use flexmonster component for react (https://www.npmjs.com/package/react-flexmonster)
When I make some modifications the current flexmonster component shows me this error : this.TD[this.j5] is null
I know that Flexmonster works on CSR (client side rendering) and I used a custom debounce hook to wait before excute any flexmonster functions .
Flexmonster component code :
import { useRef } from 'react';
import dynamic from 'next/dynamic';
import useDebounce from '#hooks/useDebounce';
import 'flexmonster/flexmonster.css';
const DynamicFlexMonster = dynamic(() => import('react-flexmonster'), {
ssr: false,
});
const Flexmonster = ({
dataSource = [],
rows = [],
columns = [],
measures = [],
formats = {},
viewType,
gridType,
chartType,
}) => {
const flexmonsterDataStructure = {
dataSource: {
data: dataSource,
},
slice: {
rows,
columns,
measures,
},
options: {
viewType,
grid: {
type: gridType,
showHeader: false,
showTotals: false,
showGrandTotals: 'off',
},
chart: {
type: chartType,
},
showEmptyData: true,
},
formats,
};
const ref = useRef(null);
const [debounceReport, setDebounceReport] = useDebounce(null);
const onReportComplete = () => {
setDebounceReport(ref.current, 1000);
if (debounceReport) {
console.log('>>>>', ref.current.flexmonster.getReport());
}
};
return (
<>
<DynamicFlexMonster
ref={ref}
toolbar={false}
width="100%"
report={flexmonsterDataStructure}
reportcomplete={onReportComplete}
/>
</>
);
};
export default Flexmonster;
I was facing the same issue, the main problem is Flexmonster use the window element so when you are working with an SSR framework like Nextjs you will need to call the all page where you display your Flexmonster component as SSR: false.
From your code, you will have to call your Flexmonster component like this:
/* pages/my-flexmonster-component-page */
import dynamic from 'next/dynamic';
const Flexmonster = dynamic(() => import('#components/Flexmonster'), {
ssr: false,
});
export default function MyFlexmonsterComponentPage(){
return (
<>
<Flexmonster/>
</>
);
}

Nextjs dynamic routes with next-i18next build error

I have an edit page that will be rendered with an id parameter and it works fine when application is running but while building the nextjs app I get this error
[Error: ENOENT: no such file or directory, rename 'C:\Users\Ahsan Nisar\Documents\GitHub\customer-portal\frontend.next\export\en\companies\edit[id].html' -> 'C:\Users\Ahsan Nisar\Documents\GitHub\customer-portal\frontend.next\server\pages\en\companies\edit[id].html']
the full error
I am not sure what this error is related to or what mistake am I making in my code that this error is occuring during build time.
Here is the code of my page
import { WithAuthorization } from 'common/roq-hocs';
import { MainLayout } from 'layouts';
import { useTranslation } from 'next-i18next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
import React, { FunctionComponent } from 'react';
import { CompaniesEditView } from 'views/companies-edit';
const CompanyCreatePage: FunctionComponent = () => {
const { t } = useTranslation('companiesEdit');
return (
<MainLayout title={t('title')}>
<WithAuthorization
permissionKey="companies.update"
failComponent={
<div className="mt-16 text-2xl text-center text-gray-600">
<span>{t('noView')}</span>
</div>
}
>
<CompaniesEditView />
</WithAuthorization>
</MainLayout>
);
};
export const getStaticProps = async ({ locale }) => ({
props: {
...(await serverSideTranslations(locale, ['common', 'companiesEdit'])),
},
});
export const getStaticPaths = () => ({
paths: ['/companies/edit/[id]'],
fallback: true,
});
export default CompanyCreatePage;
I think that the problem might be that you are not returning the expected paths model in getStaticPaths function.
Minimal example of this page:
import { GetStaticPaths, GetStaticProps } from 'next';
import { useRouter } from 'next/router';
const CompanyCreatePage = () => {
const router = useRouter();
const { id } = router.query;
return (
<div>
<h1>Company Create Page Content for id: {id}</h1>
</div>
);
};
export const getStaticPaths: GetStaticPaths = async () => {
// Get all possible 'id' values via API, file, etc.
const ids = ['1', '2', '3', '4', '5']; // Example
const paths = ids.map(id => ({
params: { id },
}));
return { paths, fallback: false };
};
export const getStaticProps: GetStaticProps = async context => {
return { props: {} };
};
export default CompanyCreatePage;
Then, navigating to the page /users/edit/3/ returns the following content
Take into account that the fallback param in getStaticPaths changes the behavior of getStaticProps function. For reference, see the documentation

Reference Error:Navigator not defined with nextjs

My code is like this:
import React, { useEffect } from 'react';
import alanBtn from '#alan-ai/alan-sdk-web';
const alanKey = my key;
const App = () => {
useEffect(() => {
alanBtn({
key: alanKey,
onCommand: ({ command }) => {
alert('This code was executed');
}
})
}, []);
return (
<div><h1>Alan AI News Application</h1></div>);
}
export default App;
But i am getting the error as:
Reference Error:Navigator not defined..
How to fix it?
Browser objects like window , navigator etc should be define in useEffect first before use.
const [pageURL, setPageURL] = useState("");
const [isNativeShare, setNativeShare] = useState(false);
useEffect(() => {
setPageURL(window.location.href);
if (navigator.share) {
setNativeShare(true);
}
}, []);
// Now, use can use pageURL , isNativeShare in code
This is not an issue with your Next.js code it's just the way you are supposed to call the alan-ai library.
Below is the solution that should work for you.
import React, { useEffect } from "react";
const alanKey = "my key";
function App() {
useEffect(() => {
const alanBtn = require("#alan-ai/alan-sdk-web");
alanBtn({
key: "myKey",
rootEl: document.getElementById("alan-btn")
});
}, []);
return (
<div>
<h1>Alan AI News Application</h1>
</div>
);
}
export default App;
Here is the discussion link for the same https://github.com/alan-ai/alan-sdk-web/issues/29#issuecomment-672242925.
Hope this solves your issue.
Happy Coding.

How to add firebase screen tracking analytics with React Native React Navigation when using createStackNavigator?

I have a React Native app and am using React Navigation. I am now trying to add screen tracking analytics with firebase.
I am following this documentation, which has this sample code:
import analytics from '#react-native-firebase/analytics';
import { NavigationContainer } from '#react-navigation/native';
<NavigationContainer
ref={navigationRef}
onStateChange={state => {
const previousRouteName = routeNameRef.current;
const currentRouteName = getActiveRouteName(state);
if (previousRouteName !== currentRouteName) {
analytics().setCurrentScreen(currentRouteName, currentRouteName);
}
In my code, however, I am creating my base NavigationContainer with a function like so:
export default createStackNavigator(
{
Home: MainTabNavigator,
SignIn: SignInNavigator,
},
{
transitionConfig: dynamicModalTransition,
headerMode: 'none',
initialRouteName: 'Home',
},
);
What is the best way to integrate the code from the example?
The problem is because you are on react-navigation v4.x.x, but the example you have is for v5.x.x.
In v4, event listeners can be added on AppContainer.
The example below is for v4.
import React from 'react';
import { createAppContainer, createStackNavigator } from 'react-navigation';
function getActiveRouteName(navigationState) {
if (!navigationState) {
return null;
}
const route = navigationState.routes[navigationState.index];
if (route.routes) {
return getActiveRouteName(route);
}
return route.routeName;
}
const nav = createStackNavigator({...});
const AppContainer = createAppContainer(nav);
export default () => {
return <AppContainer
onNavigationStateChange={(prevState, currentState, action) => {
const currentRouteName = getActiveRouteName(currentState);
const previousRouteName = getActiveRouteName(prevState);
if (previousRouteName !== currentRouteName) {
analytics().setCurrentScreen(currentRouteName, currentRouteName);
}
}}
/>
}
I'm using NavigationContainer and createStackNavigator, too and this is how I did it, like in the example for screen tracking at reactnavigation.org
import * as Analytics from 'expo-firebase-analytics';
import { useRef } from 'react';
import { NavigationContainer } from '#react-navigation/native';
export default () => {
const navigationRef = useRef();
const routeNameRef = useRef();
return (
<NavigationContainer
ref={navigationRef}
onReady={() =>
(routeNameRef.current = navigationRef.current.getCurrentRoute().name)
}
onStateChange={async () => {
const previousRouteName = routeNameRef.current;
const currentRouteName = navigationRef.current.getCurrentRoute().name;
if (previousRouteName !== currentRouteName) {
// The line below uses the expo-firebase-analytics tracker
// https://docs.expo.io/versions/latest/sdk/firebase-analytics/
// Change this line to use another Mobile analytics SDK
await analytics().logScreenView({
screen_name: currentRouteName,
screen_class: currentRouteName
});
}
// Save the current route name for later comparison
routeNameRef.current = currentRouteName;
}}
>
{/* ... */}
</NavigationContainer>
);
};

Next.js + Redux server side rendering: Has data, but doesn't render on server side

I'm trying to add redux integration to my Next.js app, but I can't get serverside rendering working the way it should. I based my implementation off the official nextjs redux example.
In the end, when the page comes back from the server, the data is present as JSON data in the output, but the actual rendering based on this data did not happen. The weird thing is that before I used redux, the content DID render the way it should.
Naturally, I'm also getting React's checksum warning, indicating that the markup on the server is different.
I have no idea how to make this work properly on the server side. Is there something that I'm missing?
Here's the HTML generated by Next.js:
<h1 data-reactid="3">Test page</h1>
</div></div></div><div id="__next-error"></div></div><div><script>
__NEXT_DATA__ = {"props":{"isServer":true,"store":{},
"initialState":{"authors":{"loading":false,"items":{"4nRpnr66B2CcQ4wsY04CIQ":… }
,"initialProps":{}},"pathname":"/test","query":{},"buildId":1504364251326,"buildStats":null,"assetPrefix":"","nextExport":false,"err":null,"chunks":[]}
module={}
__NEXT_LOADED_PAGES__ = []
__NEXT_LOADED_CHUNKS__ = []
__NEXT_REGISTER_PAGE = function (route, fn) {
__NEXT_LOADED_PAGES__.push({ route: route, fn: fn })
}
__NEXT_REGISTER_CHUNK = function (chunkName, fn) {
__NEXT_LOADED_CHUNKS__.push({ chunkName: chunkName, fn: fn })
}
</script><script async="" id="__NEXT_PAGE__/test" type="text/javascript" src="/_next/1504364251326/page/test"></script><script async="" id="__NEXT_PAGE__/_error" type="text/javascript" src="/_next/1504364251326/page/_error/index.js"></script><div></div><script type="text/javascript" src="/_next/1504364251326/manifest.js"></script><script type="text/javascript" src="/_next/1504364251326/commons.js"></script><script type="text/javascript" src="/_next/1504364251326/main.js"></script></div></body></html>
AS you can see, the initialState value is populated, it contains all the required data, but the DOM still shows empty!.
If I render the dom on the client side, the js picks up the initial content and rerenders the page with the loaded content in place.
Here's my test page JS file:
import React from 'react'
import map from 'lodash.map';
import { initStore } from '../lib/store';
import * as actions from '../lib/actions';
import withRedux from 'next-redux-wrapper';
class IndexPage extends React.PureComponent {
static getInitialProps = ({ store, req }) => Promise.all([
store.dispatch(actions.fetchAll)
]).then( () => ({}) )
render() {
const latestPlants = this.props.plants.latest || [];
return (
<div>
<h1>Test page</h1>
{ map(this.props.plants.items, p => (
<div>{p.fields.name}</div>
))}
</div>
)
}
}
export default withRedux(initStore, data => data, null)(IndexPage)
For whatever it's worth, here's the action that I call above:
export const fetchAll = dispatch => {
dispatch({
type: LOADING_ALL
})
return axios.get('/api/frontpage')
.then( response => {
const data = response.data
dispatch({
type: RESET_AUTHORS,
payload: data.authors
})
dispatch({
type: RESET_PLANTS,
payload: data.plants
})
dispatch({
type: RESET_POSTS,
payload: data.posts
})
});
}
Any help with this would be greatly appreciated, I'm at a loss on how to make this work as expected. Anyone have any leads? Please also comment if there's something I can clarify.
I recommend to split the code in different parts. First, I'll create a store, with something like this:
import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import reducer from './reducers'
export const initStore = (initialState = {}) => {
return createStore(reducer, initialState, applyMiddleware(thunkMiddleware))
}
Then I'll create the store with the types to handle:
const initialState = {
authors: null,
plants: null,
posts: null
}
export default (state = initialState, action) => {
switch (action.type) {
case 'RESET':
return Object.assign({}, state, {
authors: action.authors,
plants: action.plants,
posts: action.posts
})
default:
return state
}
}
In the actions I'll have something like this:
export const fetchAll = dispatch => {
return axios.get('/api/frontpage')
.then( response => {
const data = response.data
dispatch({
type: 'RESET',
authors: data.authors,
plants: data.plants,
posts: data.posts
})
});
}
The index will be something like this:
import React from 'react'
import { initStore } from '../store'
import withRedux from 'next-redux-wrapper'
import Main from '../components'
class Example extends React.Component {
render() {
return (
<div>
<Main />
</div>
)
}
}
export default withRedux(initStore, null)(Example)
And the component Main:
import React, {Component} from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { fetchAll } from '../../actions'
class Data extends Component {
componentWillMount() {
this.props.fetchAll()
}
render() {
const { state } = this.props
return (
<div>
<h1>Test page</h1>
{ map(state.plants.items, p => (
<div>{p.fields.name}</div>
))}
</div>
)
}
}
const mapStateToProps = (state) => {
return {
state
}
}
const mapDistpatchToProps = dispatch => {
return {
fetchAll: bindActionCreators(fetchAll, dispatch)
}
}
export default connect(mapStateToProps, mapDistpatchToProps)(Data)
Make the changes for what you need.
You can check some full examples here:
Form handler
Server Auth

Resources