I'm not able to get dynamic import to work,
//event.js
import { useEffect, useRef, useState } from "react";
import dynamic from "next/dynamic";
const NoSsrLiveStreaming = dynamic(
() => import("#/components/ui/LiveStreaming"),
{
ssr: false
}
);
async function Event() {
return (
<>
<div suppressHydrationWarning={true}>
<NoSsrLiveStreaming />
</div>
</>
);
}
export default Event;
component:
//LiveStreaming.js
function LiveStreaming() {
const [appid, setAppid] = useState("");
const [token, setToken] = useState("");
const [channel, setChannel] = useState("");
let client, agoraObj;
if (isBrowser) {
client = AgoraRTC.createClient({ codec: "h264", mode: "rtc" });
agoraObj = isBrowser() ? useAgora(client) : {};
}
const {
localAudioTrack,
localVideoTrack,
leave,
join,
joinState,
remoteUsers
} = isBrowser
? agoraObj
: {
localAudioTrack: null,
localVideoTrack: null,
leave: null,
join: null,
joinState: null,
remoteUsers: null
};
It seems like it's loading the hook useLiveStream even though I disabled SSR with dynamic import.
I do have a hook in this component useAgora(client), and this hook has window objects that threw errors. That's the reason why I wrapped this around an if browser check statement.
How do i get around this?
Related
I am working on a new project, and recently used nextjs13 for my frontend application.
When using the function generateStaticParams with the next/header library function headers(),
I get an error in dev mode.
Error occured during dev mode
But when the frontend is on using next build / next start, the error does not appear.
The main reason I am using the next/header library is due to next-auth, to gain access to cookies.
generateStaticParams is in the app/detail/[questionId]/page.tsx file
next/headers is in app/layout.tsx file
app/page.tsx
import React from "react";
import QuestionCard from "../components/Card/QuestionCard";
import Carousel from "../components/Carousel/Carousel";
import HomeNavBar from "../components/HomeNavBar/HomeNavBar";
import { ICarousel } from "../types/carousel";
import TabNavigator from "../components/TabNavigator/TabNavigator";
const getGoogleSession = async () => {};
const getQuestionList = async () => {
const response = await fetch(`https://pioneroroom.com/questionlist`);
const data = await response.json();
return data;
};
const page = async ({ Question }: any) => {
// const imageArr = await getCarouselImages();
const data = await getQuestionList();
return (
<div className="main">
<HomeNavBar />
{/* <Carousel carousel={imageArr} /> */}
<div className="contentbody">
{data.data.map((e: any) => {
return <QuestionCard key={e.questionId} question={e} />;
})}
</div>
<TabNavigator activeLink={""} />
</div>
);
};
export default page;
app/layout.tsx
import { Roboto, Noto_Sans_KR } from '#next/font/google';
import NavBar from '../components/HomeNavBar/HomeNavBar';
import '../styles/globals.css';
import SessionContainer from '../components/Providers/SessionProvider';
import '../styles/globals.css';
import { unstable_getServerSession } from 'next-auth';
import { getSession } from '../utils/helper/session';
import { cookies, headers } from 'next/headers';
import HomeNavBar from '../components/HomeNavBar/HomeNavBar';
import TabNavigator from '../components/TabNavigator/TabNavigator';
const noto = Noto_Sans_KR({
weight: '400',
fallback: ['Roboto'],
subsets: ['latin'],
});
const RootLayout = async ({ children }: any) => {
const { segment } = children.props.childProp;
const session = await getSession(headers().get('cookie') ?? '');
const nextCookies = cookies();
return (
<html className={noto.className}>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>asdf</title>
</head>
<body>
<SessionContainer session={session}>{children}</SessionContainer>
</body>
</html>
);
};
export default RootLayout;
app/detail/[questionId]/page.tsx
import { headers } from 'next/headers';
import React, { use } from 'react';
import { getSession } from '../../../utils/helper/session';
const fetchPost = async (id: any) => {
const res = await fetch(`https://pioneroroom.com/questionlist/${id}`);
return await res.json().then((res) => res.data);
};
const DetailIdPage = async ({ params }: any) => {
console.log('params.questionId', params.questionId);
const post = await fetchPost(params.questionId);
return (
<div>
<p>{JSON.stringify(post)}</p>
</div>
);
};
// BUG: generateStaticParams 함수가 현재 dev 모드에서 동작하지 않음.
// dynamic headers( next/headers )의 cookie등을 불러올 때 오류를 일으키고,
// dev mode에서 이 함수와 결합하여 사용하면 dynamic server usage: headers error 발생함.
/*
export async function generateStaticParams() {
const res = await fetch('https://pioneroroom.com/questionlist');
const data = await res.json();
const arr = data.data.map((e: any) => {
console.log('map', e.questionId);
return {
questionId: String(e.questionId),
};
});
return arr;
}
*/
export default DetailIdPage;
Erasing either both of the code (generateStaticParams or next/header) solves the problem. No errors occuring in dev mode.
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/>
</>
);
}
I am using react-redux with redux and redux-toolkit. And according to this example, i created an async dispatch that calls the reducer action when resolved.
import { createSlice } from "#reduxjs/toolkit";
import axios from "axios";
export const BlogSlice = createSlice({
name: "Blog",
initialState: {
BlogList: null,
},
reducers: {
getBlogList: (state, action) => {
console.log(action.payload);
state.BlogList = action.payload;
}
},
});
export const { getBlogList } = BlogSlice.actions;
export const getBlogListAsync = (user_id) => (dispatch) => {
axios.get(`/api/blog/getblogs/${user_id}`).then((res) => {
console.log(res.data);
dispatch(getBlogList(res.data.result));
});
};
export const selectBlogList = (state) => state.Blog.BlogList;
export default BlogSlice.reducer;
I have used it in a component accordingly so that, the component dispatches getBlogListAsync and that logs the res.data but getBlogList is not being dispatched. I tried putting other console.log() but don't understand what is wrong.
A similar Slice is working perfectly with another Component.
It is hard to say for sure what's wrong here because there is nothing that is definitely wrong.
res.data.result?
You are logging res.data and then setting the blog list to res.data.result. My best guess as to your mistake is that res.data.result is not the the correct property for accessing the blogs, but I can't possibly know that without seeing your API.
console.log(res.data);
dispatch(getBlogList(res.data.result));
missing middleware?
Is there any chance that "thunk" middleware is not installed? If you are using Redux Toolkit and omitting the middleware entirely, then the thunk middleware will be installed by default. Also if this were the case you should be getting obvious errors, not just nothing happening.
it seems fine...
I tested out your code with a placeholder API and I was able to get it working properly. Maybe this code helps you identify the problem on your end. Code Sandbox Demo.
import React from "react";
import { createSlice, configureStore } from "#reduxjs/toolkit";
import axios from "axios";
import { Provider, useDispatch, useSelector } from "react-redux";
export const BlogSlice = createSlice({
name: "Blog",
initialState: {
BlogList: null
},
reducers: {
getBlogList: (state, action) => {
console.log(action.payload);
state.BlogList = action.payload;
}
}
});
export const { getBlogList } = BlogSlice.actions;
const store = configureStore({
reducer: {
Blog: BlogSlice.reducer
}
});
export const getBlogListAsync = (user_id) => (
dispatch: Dispatch
) => {
// your url `/api/blog/getblogs/${user_id}`
const url = `https://jsonplaceholder.typicode.com/posts?userId=${user_id}`; // placeholder URL
axios.get(url).then((res) => {
console.log(res.data);
// your list: res.data.result <-- double check this
const list = res.data; // placeholder list
dispatch(getBlogList(list));
});
};
export const selectBlogList = (state) => state.Blog.BlogList;
const Test = () => {
const dispatch = useDispatch();
const blogs = useSelector(selectBlogList);
const user_id = "1";
return (
<div>
<button onClick={() => dispatch(getBlogListAsync(user_id))}>
Load Blogs
</button>
<h3>Blog Data</h3>
<div>{JSON.stringify(blogs)}</div>
</div>
);
};
export default function App() {
return (
<Provider store={store}>
<Test />
</Provider>
);
}
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.
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>
);
};