Next.js Doesn't Fetch Data When I Use Layout System - reactjs

I need to use a layout system like in the app.tsx, but I am having a problem. When I create a static content there is not a problem, but when I fetch some data, Next.js doesn't show me the content.
When I use if statement before return instead of renderLayout, it doesn't show me css styles except index.tsx. When I use a layout system like in the app.tsx, it doesn't fetch the data and show me the content. Is there any idea to fix this problem?
app.tsx
import '../styles/globals.css'
import type { AppProps } from 'next/app'
import Header from '../components/Header'
import Footer from '../components/Footer'
import { ThemeProvider, PartialTheme } from "#fluentui/react";
import Layout from '../components/Layout';
const bodyTheme: PartialTheme = {
semanticColors: {
bodyBackground: 'gray',
},
};
function MyApp({ Component, pageProps }: AppProps) {
/* if (Component.getLayout) {
return Component.getLayout(<Component {...pageProps} />)
} */
const { layoutProps, ...modifiedPageProps } = pageProps;
const renderLayout = Component.getLayout ?? Layout
return (
<>
<ThemeProvider style={{ minHeight: "82vh" }} theme={bodyTheme}>
{/* <Component {...pageProps} /> */}
{renderLayout(<Component {...modifiedPageProps} />, layoutProps)}
</ThemeProvider>
</>
)
}
export default MyApp;
at index.tsx page, I have a basic system that only fetches data and shows it, but with this layout system the data cannot be fetched, so the page seems empty.
index.tsx
import type { NextPage } from 'next'
import Head from 'next/head'
import styles from '../styles/Home.module.css'
import { ThemeProvider, PartialTheme } from '#fluentui/react/lib/Theme';
import { GetServerSideProps } from 'next'
import { useMemo } from 'react';
const lightTheme: PartialTheme = {
semanticColors: {
bodyBackground: 'rgb(107, 123, 192)',
bodyText: 'white',
},
};
const Home = ({ data }) => {
const dataMap = useMemo(() => {
return data;
}, [data])
return (
<div className={styles.main}>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<div className={styles.information}>
<h2>Fake API Company</h2>
<p style={{ color: "#fff" }}>As Fake API Company, we are happy to give you great service</p>
<p style={{ backgroundColor: "rgb(107, 123, 192)", color: "#fff", padding: "20px", borderRadius: "10px" }}>Some of Our Employees</p>
</div>
<div style={{ margin: "20px", display: "flex", flexWrap: "wrap", justifyContent: "center" }}>
{
dataMap.map(item => (
<ThemeProvider key={item.id} style={{ margin: "20px", padding: "20px", width: "250px", height: "200px", display: "flex", flexDirection: "column", justifyContent: "space-evenly", alignItems: "flex-start" }} theme={lightTheme}>
<div>Name: {item.name}</div>
<div>Email: {item.email}</div>
<div>Phone: {item.phone}</div>
<div>Website: {item.website}</div>
</ThemeProvider>
))}
</div>
</div>
)
}
export default Home;
type Data = {}
export const getServerSideProps: GetServerSideProps = async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/users");
const data: Data = await res.json();
return {
props: {
data
}
}
}
I will be very glad if someone can help me about this problem.

Related

Dynamic URL in React

I'm working on a React project with Redux and I'm consuming a Rest API, I need to implement a functionality where when I select a project from a list and I need to load the project ID in the URL and direct to another screen where a sidebar with the options is loaded. navigation of this project.
Example: Layout
I managed to load the project's Id in the URL and retrieve this ID in the project's home screen, the problem is to store the project's Id and set this ID in the next selected URLs, for example:
path: '/project/:id/companies'
path: '/project/:id/currencies'
path: '/project/:id/settings'
List of projects:
Capture the project id and arrow the url:
href={`#/project/${row.id}/main`}
Routes:
path: '/project/:id/main',
exact: true,
name: 'projectMain',
component: RequireAuth(ProjectMain),
Retrieve ID in main
import { useParams } from 'react-router-dom';
...
const { id } = useParams();
The problem is in the sidebar, where I load a list of items with the path, I'm not able to pass the project id in this list.
Complementando a pergunta
In Sidebar I'm using useHistory(), the problem is that the path comes static by 'props' through importing a file into my template, as you can see below:
Template
import React from 'react';
import { Grid, makeStyles } from '#material-ui/core';
import {
AppContent,
AppHeader,
SidebarApp,
} from '../components/index';
import itemsProject from '../components/itemsSidebar/itemsProject';
const useStyles = makeStyles(theme => ({
appContent: {
paddingLeft: 240,
width: '100%',
backgroundColor: theme.palette.background.paper,
},
}));
const ProjectLayout = () => {
const classes = useStyles();
return (
<div className={classes.appContent}>
<AppHeader />
<Grid container direction="row">
<SidebarApp items={itemsProject} />
<AppContent />
</Grid>
</div>
);
};
export default ProjectLayout;
Sidebar:
/* eslint-disable react/jsx-no-duplicate-props */
import React from 'react';
import List from '#material-ui/core/List';
import ListItem from '#material-ui/core/ListItem';
import Divider from '#material-ui/core/Divider';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
import ExpandLessIcon from '#material-ui/icons/ExpandLess';
import Collapse from '#material-ui/core/Collapse';
import {
alpha,
Box,
Card,
ListSubheader,
makeStyles,
Typography,
} from '#material-ui/core';
import { useHistory, useLocation, useParams } from 'react-router-dom';
import translate from '../providers/i18n/translate';
const useStyles = makeStyles(theme => ({
sidebar: {
background: theme.palette.background.dark,
width: 240,
height: '100vh',
border: '1px solid rgba(0, 0, 0, 0.1)',
display: 'flex',
flexDirection: 'column',
position: 'absolute',
paddingTop: 64,
top: 0,
left: 0,
},
sidebarItem: {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
},
sidebarItemContent: {
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
overflow: 'hidden',
display: 'flex',
alignItems: 'center',
width: '100%',
},
sidebarItemIcon: {
marginRight: 6,
},
sidebarItemText: {
width: '100%',
},
sidebarItemExpandArrow: {
fontSize: '1.2rem !important',
},
sidebarItemExpandArrowExpanded: {
fontSize: '1.2rem !important',
color: theme.palette.primary.main,
fontWeight: 'bold',
},
active: {
background: alpha(theme.palette.primary.light, 0.2),
},
}));
function SidebarItem({ depthStep = 10, depth = 0, expanded, item, ...rest }) {
const [collapsed, setCollapsed] = React.useState(true);
const { label, items, Icon, onClick: onClickProp } = item;
const classes = useStyles();
const history = useHistory();
const location = useLocation();
function toggleCollapse() {
setCollapsed(prevValue => !prevValue);
}
function onClick(e) {
if (Array.isArray(items)) {
toggleCollapse();
}
if (onClickProp) {
onClickProp(e, item);
history.push(item.path);
}
}
let expandIcon;
if (Array.isArray(items) && items.length) {
expandIcon = !collapsed ? (
<>
<ExpandLessIcon className={classes.sidebarItemExpandArrowExpanded} />
</>
) : (
<ExpandMoreIcon className={classes.sidebarItemExpandArrow} />
);
}
return (
<>
<ListItem
className={classes.sidebarItem}
onClick={onClick}
button
dense
className={location.pathname === item.path ? classes.active : null}
{...rest}
>
<div
style={{ paddingLeft: depth * depthStep }}
className={classes.sidebarItemContent}
>
{Icon && (
<Icon
className={classes.sidebarItemIcon}
fontSize="small"
color="primary"
/>
)}
<div className={classes.sidebarItemText}>{label}</div>
</div>
{expandIcon}
</ListItem>
<Collapse in={!collapsed} timeout="auto" unmountOnExit>
{Array.isArray(items) ? (
<List disablePadding dense>
{items.map((subItem, index) => (
<React.Fragment key={`${subItem.name}${index}`}>
{subItem === 'divider' ? (
<Divider style={{ margin: '6px 0' }} />
) : (
<SidebarItem
depth={depth + 1}
depthStep={depthStep}
item={subItem}
/>
)}
</React.Fragment>
))}
</List>
) : null}
</Collapse>
</>
);
}
function Sidebar({ items, depthStep, depth, expanded }) {
const classes = useStyles();
const { key } = useParams();
return (
<Card elevation={0} className={classes.sidebar}>
<List
disablePadding
dense
subheader={
<ListSubheader component="div" id="nested-list-subheader">
{translate('sidebarMenuSettings')}
<Typography>
<Box>{key}</Box>
</Typography>
</ListSubheader>
}
>
{items.map((sidebarItem, index) => (
<React.Fragment key={`${sidebarItem.name}${index}`}>
{sidebarItem === 'divider' ? (
<Divider style={{ margin: '6px 0' }} />
) : (
<SidebarItem
depthStep={depthStep}
depth={depth}
expanded={expanded}
item={sidebarItem}
/>
)}
</React.Fragment>
))}
</List>
</Card>
);
}
export default Sidebar;
Sidebar list items
function onClick(e, item) {}
const itemsProject = [
{
name: 'companies',
label: translate('sidebarProjectCompanies'),
Icon: CompanyIcon,
path: '/project/:id/companies',
onClick,
}
{
name: 'currencies',
label: translate('sidebarProjectCurrencies'),
Icon: CurrencyIcon,
path: '/project/:id/currencies',
onClick,
}
];
export default itemsProject;
How can I pass the ID variable on the Sidebar list items?
I thank you for your help!
You can use ES6 template literals as follows.
path: `/project/${id}/companies`
Since you already defined your path, you just need to use useHistory and navigate to the new link
import { useHistory } from 'react-router';
...
const history = useHistory();
...
// call this whenever you want to navigate
history.push(`/project/${id}/currencies`);

Material UI is not working properly with Next.js

These are the problems I faced with Next.js and Material UI, even though I am following the methods mentioned in Material UI docs.
I am getting this error, if I use props with makeStyles:
I am getting if I pass state as props
const useStyles = makeStyles((theme: Theme) => ({
root: {
background: "#EFEFEF",
minHeight: (props: any) => (props.open ? "150vh" : "100vh"),
},
},
}));
const Profile = () => {
const [open, setOpen] = useState(false);
const classes = useStyles({ open });
const handleOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<div className={classes.root}>
<Layout authRoute={false} showNavbar={false}>
<Container maxWidth="lg">
<Header method={method} />
<div className={classes.btnContainer}>
<Button
variant="contained"
color="secondary"
className="yesBtn"
onClick={handleOpen}>
<IoMdCheckmark />
Yes
</Button>
<Button
variant="contained"
color="default"
className="noBtn"
onClick={() => router.push("/")}>
<TiDeleteOutline />
No
</Button>
</div>
<ProfileModal handleClose={handleClose} open={open} />
</Container>
</Layout>
</div>
);
};
export default Profile;
Media query is not working in production (theme.breakpoints.down("sm")).
export const useButtonStyle = makeStyles(theme => ({
submitBtn: {
padding: "12px 16px",
borderRadius: theme.shape.borderRadius,
position: "absolute",
bottom: "25%",
display: "block",
left: "0%",
right: "0%",
width: "83.5%",
margin: " auto",
[theme.breakpoints.down("xs")]: {
bottom: "35%",
width: "88%",
},
"& .MuiButton-label": {
display: "flex",
justifyContent: "center",
alignItems: "center",
"& .MuiCircularProgress-root": {
height: "20px",
width: "20px",
marginRight: "10px",
},
},
},
root: {
position: "relative",
backgroundColor: theme.palette.secondary.dark,
minHeight: "100vh",
[theme.breakpoints.up("sm")]: {
padding: "2rem 0.2rem",
"& .overlay": {
display: "none",
},
},
[theme.breakpoints.down("sm")]: {
"& .MuiContainer-root": {
paddingLeft: "0",
paddingRight: "0",
},
},
},
}));
Here is _document.tsx file
import Document, { Html, Head, Main, NextScript } from "next/document";
import { ServerStyleSheets } from "#material-ui/styles";
class MyDocument extends Document {
static async getInitialProps(ctx: any) {
const sheet = new ServerStyleSheets();
const originalRenderPage = ctx.renderPage;
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App: any) => (props: any) =>
sheet.collect(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
};
} finally {
ctx.renderPage(sheet);
}
}
render() {
return (
<Html>
<Head>
<link
rel="shortcut icon"
type="image/png"
href="../static/favicon.ico"
/>
<style>{`body { margin: 0 } /* custom! */`}</style>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
</Head>
<body className="custom_class">
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
This is _app.tsx file
import { ApolloProvider } from "#apollo/client";
import CssBaseline from "#material-ui/core/CssBaseline";
import { ThemeProvider } from "#material-ui/core/styles";
import Head from "next/head";
import React from "react";
import theme from "../src/theme";
import "../styles/styles.scss";
import { withApollo } from "../src/utils/apollo";
import App from "next/app";
class MyApp extends App<any> {
componentDidMount() {
const jssStyles = document.querySelector("#jss-server-side");
if (jssStyles) {
jssStyles.parentElement!.removeChild(jssStyles);
}
}
render() {
const { Component, pageProps, apolloClient } = this.props;
return (
<>
<Head>
<title>Beauty wall spot</title>
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width"
/>
</Head>
<ThemeProvider theme={theme}>
<CssBaseline />
<ApolloProvider client={apolloClient}>
<Component {...pageProps} />
</ApolloProvider>
</ThemeProvider>
</>
);
}
}
export default withApollo(MyApp);
Install 'npm install #mui/styles'
Then Import: import { makeStyles } from '#mui/styles';

Next js: Error: Objects are not valid as a React child (found: Error: Response not successful: Received status code 401)

This app shows Github issues with graphql API.
I didn't change anything after finishing the app but I got this error.
I used Next js, Typescript, Material UI, Tailwind css and GraphQL for this project.
Index Component
import React, { useState } from "react"
import { Typography, Container, makeStyles } from "#material-ui/core"
import SearchBar from "../components/SearchBar/SearchBar"
import RepositoryList from "../components/RepositoryList/RepositoryList"
import Head from "next/head"
const useStyles = makeStyles({
title: {
marginTop: "1rem",
marginBottom: "1rem",
textAlign: "center",
},
})
const App = () => {
const classes = useStyles()
const [searchTerm, setSearchTerm] = useState<string>("")
return (
<>
<Head>
<title>GraphQL Github Client</title>
</Head>
<Container maxWidth={"sm"}>
<div className="mt-10 mb-5">
<Typography variant={"h3"} className={classes.title}>
GraphQL Github Client
</Typography>
</div>
<SearchBar
className="mb-10"
value={searchTerm}
onChange={setSearchTerm}
/>
<RepositoryList searchTerm={searchTerm} />
</Container>
</>
)
}
export default App
RepositoryList Component
import React, { useEffect, useState } from "react"
import { Typography, CircularProgress, makeStyles } from "#material-ui/core"
import { useQuery } from "#apollo/react-hooks"
import { SEARCH_FOR_REPOS } from "../../Queries/queries"
import Repository from "../Repository/Repository"
interface RepositoryListProps {
searchTerm?: string
}
const useStyles = makeStyles({
note: {
marginTop: "1rem",
textAlign: "center",
},
spinnerContainer: {
display: "flex",
justifyContent: "space-around",
marginTop: "1rem",
},
})
const RepositoryList: React.FC<RepositoryListProps> = ({ searchTerm }) => {
const classes = useStyles()
const [expandedRepo, setExpandedRepo] = useState(null)
const { data, loading, error } = useQuery(SEARCH_FOR_REPOS, {
variables: { search_term: searchTerm },
})
useEffect(() => {
setExpandedRepo(null)
}, [data])
if (loading) {
return (
<div className={classes.spinnerContainer}>
<CircularProgress />
</div>
)
}
if (error) {
return (
<Typography
variant={"overline"}
className={classes.note}
component={"div"}
color={"error"}
>
{error}
</Typography>
)
}
if (!data.search.repositoryCount) {
return (
<Typography
variant={"overline"}
className={classes.note}
component={"div"}
>
There are no such repositories!
</Typography>
)
}
return (
<div>
{data.search.edges.map(
(
repo: { edges: { id: number } },
i: string | number | ((prevState: null) => null) | null | any
) => (
<>
<Repository
repo={repo}
expanded={expandedRepo === i}
onToggled={() => setExpandedRepo(i)}
key={repo.edges.id}
/>
</>
)
)}
</div>
)
}
export default RepositoryList
Repository Component
import React from "react"
import {
ExpansionPanel,
ExpansionPanelSummary,
ExpansionPanelDetails,
Typography,
Chip,
makeStyles,
} from "#material-ui/core"
import StarIcon from "#material-ui/icons/Star"
import PeopleIcon from "#material-ui/icons/People"
import IssueList from "../IssueList/IssueList"
const useStyles = makeStyles({
root: {
marginTop: "1rem",
},
summaryContainer: {
flexDirection: "column",
},
summaryHeader: {
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
marginBottom: "1rem",
},
chip: {
marginLeft: "0.5rem",
},
})
interface RepositoryProps {
repo: any
expanded: boolean
onToggled: any
}
const Repository: React.FC<RepositoryProps> = ({
repo,
expanded,
onToggled,
}) => {
const {
node: {
name,
descriptionHTML,
owner: { login },
stargazers: { totalCount: totalStarCount },
},
} = repo
const classes = useStyles()
return (
<ExpansionPanel
expanded={expanded}
onChange={onToggled}
className={classes.root}
>
<ExpansionPanelSummary classes={{ content: classes.summaryContainer }}>
<div className={classes.summaryHeader}>
<Typography variant={"h6"}>{name}</Typography>
<div>
<Chip
label={`by ${login}`}
avatar={<PeopleIcon />}
className={classes.chip}
/>
<Chip
label={totalStarCount}
avatar={<StarIcon />}
className={classes.chip}
/>
</div>
</div>
<Typography
variant={"caption"}
dangerouslySetInnerHTML={{ __html: descriptionHTML }}
component={"div"}
/>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
{expanded && <IssueList repoName={name} repoOwner={login} />}
</ExpansionPanelDetails>
</ExpansionPanel>
)
}
export default Repository
These are my components.
What should I do for fixing this problem?
It looks like the issue is in this spot where you do {error}. I would double check what error actually is but it looks like its an object and not a string like you are using it
<Typography
variant={"overline"}
className={classes.note}
component={"div"}
color={"error"}
>
{error}
</Typography>

What is the proper way of using the styling defined inside createMuiTheme alongside with Material-UI's useStyles?

import React from 'react';
import Component from './components/Component';
import { createMuiTheme, makeStyles, ThemeProvider } from '#material-ui/core/styles';;
const theme = createMuiTheme({
container: {
width: '100%',
paddingRight: '15px',
paddingLeft: '15px',
marginRight: 'auto',
marginLeft: 'auto'
},
flexColumn: {
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
}
});
function App() {
return (
<ThemeProvider theme={theme}>
<div className="App">
<Component />
</div>
</ThemeProvider>
);
}
export default App;
The theme provided above goes inside the component Component.
import React, { useState } from "react";
import { makeStyles } from '#material-ui/core/styles';
import { useTheme } from '#material-ui/core/styles';
import classNames from 'classnames';
const useStyles = makeStyles(() => ({
bar: {
flexGrow: 1,
padding: '.8rem .8rem',
lineHeight: '1.5em',
fontSize: '18px',
},
alert: {
color: 'white',
backgroundColor: 'red',
},
}));
export default function Component (props) {
const theme = useTheme();
const classes = useStyles();
const [focus, setFocus] = useState(false);
return (
<div>
<div style={theme.flexColumn} className={classNames(classes.alert, classes.bar)}>
<div>
</div>
</div>
</div>
);
}
Is this the proper way to use useTheme and className? The issue with this is that I can't use the styles defined with createMuiTheme and fetched through the ThemeProvider inside the className attribute, which means sometimes the styling inside classNames and style may conflict with one another. I couldn't find an example where the styling provided inside createMuiTheme is used with className.
If you want to reuse classes in MUI, you should create an external style file, then import this file into the components that you want to use this style. Try this:
In sharedStyles:
export const layout = {
header: {
fontSize: "1.5em",
color: "blue"
},
footer: {
fontSize: "0.8em"
}
};
const sharedStyles = theme => ({
grow: {
flexGrow: 1
},
defaultPadding: {
padding: theme.spacing.unit * 3 + "px"
},
"layout.header": layout.header
});
export default sharedStyles;
In a component:
import React from "react";
import { withStyles } from "#material-ui/core/styles";
import Paper from "#material-ui/core/Paper";
import sharedStyles, { layout } from "./sharedStyles";
import Typography from "#material-ui/core/Typography";
function Dashboard(props) {
const { classes } = props;
return (
<Paper className={classes.defaultPadding}>
<Typography variant="body1" gutterBottom>
Hello <span className={classes.someOtherStyle}>World</span>
</Typography>
<Typography
component="h2"
variant="h1"
gutterBottom
className={classes["layout.header"]}
>
Heading
</Typography>
<Typography
component="h2"
variant="h1"
gutterBottom
className={classes.header}
>
Heading 2
</Typography>
</Paper>
);
}
const styles = theme => ({
...sharedStyles(theme),
header: layout.header,
someOtherStyle: {
color: "red"
}
});
export default withStyles(styles)(Dashboard);

with useEffect API call, unable to switch to another route from the mounted component

I am calling an my API with useEffect and it works fine, but when I click on a Link component to another page I am getting:
TypeError: func.apply is not a function
Here is my component:
import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import axios from 'axios';
import { makeStyles } from '#material-ui/core/styles';
import Card from '#material-ui/core/Card';
import CardActions from '#material-ui/core/CardActions';
import CardContent from '#material-ui/core/CardContent';
import Button from '#material-ui/core/Button';
import Slide from '#material-ui/core/Slide';
import dummy from '../../dummy';
const useStyles = makeStyles({
root: {
width: "90%",
marginLeft: "auto",
marginRight: "auto",
marginTop: "80px",
},
container: {
width: "100%",
marginTop: "40px",
display: "flex",
flexWrap: "wrap",
},
card: {
flex: "20%",
minWidth: "200px",
backgroundColor: "#212121",
marginLeft: "10px",
marginRight: "10px",
marginBottom: "20px",
},
title: {
color: "white",
},
desc: {
color: "white",
},
});
const StackList = () => {
const classes = useStyles();
const [displayPosts, setDisplayPosts] = useState([])
const [isLoading, setIsLoading] = useState(true)
useEffect(async () => {
const fetchData = async () => {
const result = await axios(
'http://192.168.1.17:8000/stacks'
);
setDisplayPosts(result.data)
setIsLoading(false)
};
fetchData();
}, []);
return(
<div className={classes.root}>
<h1 style={{color: "white"}}>Stack Viewer</h1>
<div className={classes.container}>
{displayPosts.map(item =>
<Slide direction="up" in={true} timeout={800}>
<Card className={classes.card}>
<CardContent>
<h2 className={classes.title}>{item.name}</h2>
<p className={classes.desc}>By {item.author}</p>
</CardContent>
<CardActions>
<Button component={Link} to="stacks/test" size="small" style={{color:"white"}}>View Weapon Stack</Button>
</CardActions>
</Card>
</Slide>
)}
</div>
</div>
)
}
I am clicking on <Button component={Link} to="stacks/test" size="small" style={{color:"white"}}>View Weapon Stack</Button>
I can load other routes just fine from my sibling navbar component.
If I change out my useEffect call with a mock JSON response, everything works just fine.
I know this must be something simple that I am missing, but I don't understand why this is happening.

Resources