Conditional css in react/Next js - javascript

I am using Next js,I am applying conditional on component which is working,but css style changes between different component.
Code 1:
import React from "react";
import Profile from "../../components/model/Profile";
import { useAuthContext, useAuthUpdateContext } from "../../app/AuthContext"
function profile() {
const user = useAuthContext()
const { updateUser } = useAuthUpdateContext()
return user.isLoggedIn === true && user.user.userType === "Model" ? (
<div>
<Profile />
</div>
) : (
<div className="">
<h1>You are not authorized to view this page</h1>
{/* tw-mx-auto tw-mt-auto tw-font-extrabold tw-capitalize tw-text-3xl */}
</div>
)
}
export default profile;
Image of code 1 style
import React from "react";
import Profile from "../../components/model/Profile";
import { useAuthContext, useAuthUpdateContext } from "../../app/AuthContext"
function profile() {
const user = useAuthContext()
const { updateUser } = useAuthUpdateContext()
return user.isLoggedIn === true && user.user.userType === "Model" ? (
<div>
<Profile />
</div>
) : (
<div className="tw-mx-auto tw-mt-auto tw-font-extrabold tw-capitalize tw-text-3xl"> <-----// Difference is here from code 1
<h1>You are not authorized to view this page</h1>
{/* tw-mx-auto tw-mt-auto tw-font-extrabold tw-capitalize tw-text-3xl */}
</div>
)
}
export default profile;
Image of code 2 style
Components are working as expected but css style not.

If you are using CSS or SCSS modules, you will first have to import the style sheet in the component where you want to use the styles.
So in your example above, you would use something like:
import React from "react";
import Profile from "../../components/model/Profile";
import { useAuthContext, useAuthUpdateContext } from "../../app/AuthContext"
import styles from "../yourPath/../toStyles/stylesheet.module.css"
Don't forget to use "module.scss" if you are using SCSS in your project.
After that, you can treat the imported styles as object in JS code. So something like this in your code above:
<div className={styles.myClass}> <-----// Difference is here from code 1
<h1>You are not authorized to view this page</h1>
{/* tw-mx-auto tw-mt-auto tw-font-extrabold tw-capitalize tw-text-3xl */}
</div>
You can find more info in the official docs -> https://nextjs.org/docs/basic-features/built-in-css-support

Related

How to auto-indent code string in PrismJS? NextJs APP

i am trying to use PrimsJs in a react project, my objetive is create a static template page, and add snippets, i am not sure if is the best option(primsjs) but i am trying to auto-indent the code, because actually my code is rendered in one line
THIS IS MY PAGE
import { MainLayout } from "../components/layouts/MainLayout";
import { Hero1, Hero1Code} from "../theme/blocks/hero/Hero1";
export default function Home() {
return (
<MainLayout>
<h1>Home Page</h1>
<Hero1 />
<Hero1Code />
</MainLayout>
);
}
THIS IS MY PRIMSJS COMPONENT
import React, { useEffect } from "react";
import Prism from "prismjs";
import "prismjs/themes/prism-tomorrow.css";
export default function Code({ code, language }) {
useEffect(() => {
Prism.highlightAll();
}, []);
return (
<div className="Code">
<pre>
<code className={`language-${language}`}>{code}</code>
</pre>
</div>
);
}
THIS IS MY COMPONENT
import React from "react";
import { renderToString } from "react-dom/server";
import Code from "../../../components/prism/code";
export const Hero1 = () => {
return (
<section className="wrapper bg-light">
...
</section>
);
};
export const Hero1Code = () => {
const content = renderToString(<Hero1/>);
return (
<>
<div className="App">
<Code code={content} language="html" />
</div>
</>
);
};
Any help will be very welcome, also i am open to try other package
I don't think that PrismJS has such an option, in my opinion it would be best to just indent the code string before passing it to the <Code /> component.
You could use this library: https://github.com/zebzhao/indent.js
Import it:
import indent from 'indent.js';
And indent the code like this:
const content = indent.html(renderToString(<Hero1/>));
However, looking at your screenshot code example, I can see that you have a lot of divs smashed into one line. In this case, indentation would not really help, as it takes care of the relations between separate lines.
You could take a look at using a library like this, which seems to split code into separate lines.
https://www.npmjs.com/package/pretty

Reload a page after the initial load with Next.js

I have a route called "./checkout" that renders embedded elements from Xola. The issue is I am using client side routing and the page needs a refresh to load the checkout page correctly (if not, Xola elements do not show up on the DOM 1). When I try to reload the page on the initial load I get an infinite reload loop. I can't use a href for specific reasons so I need to continue to use Next.js routing. Anyway I can go about this? EDIT: I have reached out to Xola support team for further assistance.
After refresh
checkout.js
import Head from "next/head";
import { useRouter } from "next/router";
import { Container, Button } from "#mui/material";
import { makeStyles } from "#mui/styles";
import { CheckoutCard } from "../components/layout/directory";
import useIsSsr from "#/config/useSsr";
function Checkout() {
const isSsr = useIsSsr();
const router = useRouter();
const classes = useStyles();
return (
<>
{isSsr ? null : window.location.reload()}
<Head>
<title>checkout</title>
</Head>
<Container className={classes.root}>
<Button
className={classes.btn}
onClick={router.back}
color="secondary"
variant={"contained"}
>
back
</Button>
<CheckoutCard />
</Container>
</>
);
}
const useStyles = makeStyles((theme) => ({
root: { marginTop: theme.spacing(10) },
btn: { marginBottom: theme.spacing(5) },
}));
export default Checkout;
CheckoutCard.js
function CheckoutCard() {
return (
<div
className="xola-embedded-checkout"
data-seller="5f3d889683cfdc77b119e592"
data-experience="5f3d8d80d6ba9c6b14748160"
data-version="2"
id="xola-checkout"
></div>
);
}
export default CheckoutCard;
Please add one more prop to CheckoutCard component calling in checkout.js.
You need to update
<CheckoutCard
url={`https://checkout.xola.com/index.html#seller/5f3d889683cfdc77b119e592/experiences/${
url && url.slice(1)
}?openExternal=true`}
/>
to
<CheckoutCard
url={`https://checkout.xola.com/index.html#seller/5f3d889683cfdc77b119e592/experiences/${
url && url.slice(1)
}?openExternal=true`}
key={new Date().getTime()}
/>
"key" prop is to identify the component and you are going to use external service ( like iframe, not sure correctly )
So in order to render the embedded elements from Xola, you should add "key" prop for CheckoutCard component calling.

NextJs Layout Login page?

I'm covering app js with layout. I have the sidebar on the left and my pages on the right. But what I want is that the sidebar should not appear on the login page, how can I edit it?
_app.js
Layout.js
you can add a condition with pathname to showing the component or not
something like this:
const router = useRouter():
return (
...
{router.pathname !== '/login' && <Sidebar path={router.route} />}
...
)
If you have some pages that are protected and can be seen by logged in user than you would need Public and Protected Routes and you can show in your Public routes only
If this is not the case then solution mentioned by #kaveh karami is good
I'm thinking you should use Option 4 of the Persistent Layout Patterns article by Adam Wathan (the getLayout Pattern) to implement the layout and pass a prop to conditionally render the sidebar.
In this way, your Login / Register page controls the layout rendering
// Layout.js
export default function Layout({ showSidebar, children, ...rest }){
return (
...
{showSidebar && <Sidebar />}
...
)
}
export function getLayout(page, props) {
return <Layout {...props}>{page}</DefaultLayout>
}
// Login.js
import { getLayout as getDefaultLayout } from './Layout.js'
function Login(){
return (
...
)
}
Login.getLayout = page => getDefaultLayout(page, { showSidebar: true})
I would create a HOC(Higher-Order-Component) called WithSidebar:
import Main from '../../components/Main/Main';
import Sidebar from '../../components/Sidebar/Sidebar';
import classes from './WithSidebar.module.scss';
const WithSidebar = (Component) => {
return props => (
<div className={classes.WithSidebar}>
<Sidebar />
<Main className={classes.Container}>
<Component {...props} />
</Main>
</div>
);
};
export default WithSidebar;
And then export the pages that should include the sidebar like so:
import WithSidebar from '../hoc/WithSidebar/WithSidebar';
const MyPage = () => {
return (...)
}
export default WithSidebar(MyPage)
I find this approach really cleaner than conditionally rendering based on the pathname.

How can I access react context in react-styleguidist's Wrapper component?

What I want:
I'm trying to add a dynamic theme option to a react-styleguidist project I'm working on. Following the idea laid out in this unfinished and closed pr, I added a custom ThemeSwitcher component, which is a select menu that is rendered in the table of contents sidebar. Selecting an option should update the brand context, which renders the corresponding theme using styled-components' BrandProvider. It should function like the demo included with the closed pr: https://fancy-sg.surge.sh/.
What's not working:
I can't access the same context in my ThemedWrapper as is provided and updated in the StyleguideWrapper and ThemeSwitcher. Examining the tree in the React Components console, it looks like react-styleguidist may render ReactExample outside of the StyleguideRenderer, which means it loses the context from the provider in that component.
Assuming I'm correct about the context not updating in ThemedWrapper due to it being located outside of StyleGuideRenderer, two high level ideas I have (but haven't been able to figure out how to do) are:
Find the correct component that is an ancestor of both StyleGuideRenderer and ReactExample in the react-styleguidist library and add the BrandProvider there so that ThemedWrapper now has context access
Some other context configuration that I haven't found yet that will allow two components to consume the same context without having a provider as an ancestor (is this possible??)
What I have:
Here are the condensed versions of the relevant code I'm using.
brand-context.js (exports context and provider, inspired by Kent C Dodds
import React, { createContext, useState, useContext } from 'react';
const BrandStateContext = createContext();
const BrandSetContext = createContext();
function BrandProvider({ children, theme }) {
const [brand, setBrand] = useState(theme);
return (
<BrandStateContext.Provider value={brand}>
<BrandSetContext.Provider value={(val) => setBrand(val)}>
{children}
</BrandSetContext.Provider>
</BrandStateContext.Provider>
);
}
function useBrandState() {
return useContext(BrandStateContext);
}
function useBrandSet() {
return useContext(BrandSetContext);
}
export { BrandProvider, useBrandState, useBrandSet };
StyleGuideWrapper.jsx (Copy of rsg-components/StyleguideRenderer, with addition of ThemeSwitcher component to toggle theme from ui; passed in styleguide config as StyleGuideRenderer)
import React from 'react';
import cx from 'clsx';
import Styled from 'rsg-components/Styled';
import ThemeSwitcher from './ThemeSwitcher';
import { BrandProvider } from './brand-context';
export function StyleGuideRenderer({ children, classes, hasSidebar, toc }) {
return (
<BrandProvider>
<div className={cx(classes.root, hasSidebar && classes.hasSidebar)}>
<main className={classes.content}>
{children}
</main>
{hasSidebar && (
<div className={classes.sidebar} data-testid="sidebar">
<section className={classes.sidebarSection}>
<ThemeSwitcher classes={classes} />
</section>
{toc}
</div>
)}
</div>
</BrandProvider>
);
}
StyleGuideRenderer.propTypes = propTypes;
export default Styled(styles)(StyleGuideRenderer);
ThemeSwitcher.jsx
import React from 'react';
import Styled from 'rsg-components/Styled';
import { useBrandSet, useBrandState } from './brand-context';
const ThemeSwitcher = ({ classes }) => {
const brand = useBrandState();
const setBrand = useBrandSet();
const onBrandChange = (e) => setBrand(e.target.value);
const brands = ['foo', 'bar'];
return (
<label className={classes.root}>
Brand
<select value={brand} onChange={onBrandChange}>
{brands.map((brand) => (
<option key={brand} value={brand}>{brand}</option>
))}
</select>
</label>
);
};
export default Styled(styles)(ThemeSwitcher);
ThemedWrapper.jsx (passed in styleguide config as Wrapper, and wraps each example component to provide them to styled-components)
import React from 'react';
import { ThemeProvider } from 'styled-components';
import { BrandStateContext } from './brand-context';
const LibraryProvider = ({ brand, children }) => {
return (
<ThemeProvider theme={brand}>{children}</ThemeProvider>
);
};
function ThemedWrapper({ children }) {
return (
<BrandStateContext.Consumer>
{brand => (
<LibraryProvider brand={brand}>{children}</LibraryProvider>
)}
</BrandStateContext.Consumer>
);
}
export default ThemedWrapper;

Cannot set style-display of a div containing another component through a component in React.js

I am aiming to create a component containing a function, in which a button removes a separate div containing text, which is presented in React.js by another component in a separate div.
Below is the code for my app.js. I would like to set the style of "tweetSection" to "none" (contains Tweet component that provides the text), using the "TurnOff" component.
import logo from './logo.svg';
import Tweet from './Tweet';
import TurnOff from './TurnOff';
function App() {
return (
<div>
<div id="tweetSection">
<Tweet />
</div>
<div id="button">
<TurnOff />
</div>
</div>
);
}
export default App;```
Here is the code for my TurnOff component
import React from 'react';
function TurnOff(){
const toggle = () => {
document.getElementById('tweetSection').style.display = "none";
}
return(
<div>
<button onClick={toggle()}>this is a button</button>
</div>
);
}
export default TurnOff;
When I run this, I get a type error stating "TypeError: Cannot read property 'style' of null". Is there a simplistic way, or program this in a different manner in order to hide the "tweetSection" div?
A few things.
To answer why you are getting the error, it is because you are calling the function (toggle()) immeaditely with onClick={toggle()}.
Use this to avoid the problem of calling the function too early:
<button onClick={toggle}>this is a button</button>
Or:
<button onClick={() => toggle()}>this is a button</button>
It is being called as soon as it renders, which means document.getElementById('tweetSection') might be null.
You can check for this like:
const el = document.getElementById('tweetSection');
if (el) {
el.style.display = "none";
} else {
console.warn('No tweetSection element found');
}
However, a more react way to solve this problem would be to pass props:
import logo from './logo.svg';
import Tweet from './Tweet';
import TurnOff from './TurnOff';
import React, {useState} from 'react';
function App() {
const [showTweet, setShowTweet] = useState(true);
return (
<div>
{showTweet && <div id="tweetSection">
<Tweet />
</div>}
<div id="button">
<TurnOff toggle={() => {
setShowTweet(!showTweet);
}}
/>
</div>
</div>
);
}
export default App;
import React from 'react';
function TurnOff({ toggle }){
return(
<div>
<button onClick={toggle}>this is a button</button>
</div>
);
}
export default TurnOff;

Categories