Making a Materal UI card template in react - reactjs

I'm trying to make a card template in React using Material UI. I need this template so I can easily generate more cards in the future. The documentation often have the script in one single file, and never explain how to separate it and still having it to work. I don't gonna use the export import lines here just to simplify the code.
Lets say i have a Cardtemplate.jsx
const useStyles = makeStyles({
root: {
maxWidth: 345,
},
subtitle: {
fontSize: 14,
},
card:{
height: 100,
}
title:{
fontSize: 12,
}
});
const Cardtemplate = ({ classes, image, title, subtitle }) => {
return (
<Card className={classes.card}>
<CardMedia image={image} />
<Typography className={classes.title} variant={'h2'}>{title}</Typography>
<Typography className={classes.subtitle}>{subtitle}</Typography>
</Card>
);
};
export default Cardemplate;
Then I want to use the temple to generate card1.jsx
export default function Card1() {
const classes = useStyles();
return (
<Cardtemplate
classes={styles}
title={'Some title'}
subtitle={'some subtitle'}
image={'image.png'}
/>
);
}
Finally in the App.js I would render all the cards like this.
function App(){
return(
<Card1 />
<Card2 />
<Card3 />
...
...
)
};
The problem is that I getting syntaxError telling that Identifier 'useStyles' has already been declared or some undefined properties is missing. I have tried to place the const classes = useStyles(); in the cardTemplate.jsx.
I have also tried to wrap the const useStyles inside the const Cardtemplate function just to make sure that the useStyles also get exported, but all I get Is errors.
There's something I have been missing here. How can I do this the proper way without any further errors?

Your CardTemplate shouldn't receive classes from props, it should be declared on it, using the useStyles defined above, so it should look like this:
const useStyles = makeStyles({
// style
});
export default function CardTemplate({ title, subtitle }) {
const classes = useStyles();
return (
<Card className={classes.card}>
<Typography className={classes.title} variant={"h2"}>
{title}
</Typography>
<Typography className={classes.subtitle}>{subtitle}</Typography>
</Card>
);
}
Then, you can have each of your Cards importing this component and reusing, per example:
// Card1.js
export default () => {
return <CardTemplate title="Card 1" subtitle="The First" />;
};
// Card2.js
export default () => {
return <CardTemplate title="Card 2" subtitle="The Second" />;
};
// Card3.js
export default () => {
return <CardTemplate title="Card 3" subtitle="The Third" />;
};
Lastly, you can render them in any place as you seem fit, example:
ReactDOM.render(
<>
<Card1 />
<Card2 />
<Card3 />
</>,
document.querySelector("#root")
);
There is a running code sandbox I made for you. You can check it here!

Related

React Beginner - Trouble understanding useContext for dark mode

I'm completing an online program to learn ReactJS. After going over useState we are now learning useContext. Below I'll go over my current understanding of how useContext works, and where I'm facing trouble.
The goal is a simple page with a light/dark mode switch
What I currently understand as the "steps" to using useContext:
Import and initialize createContext
Wrap child components with Provider
Import useContext hook from React so we can use the Context in child components
Access the user Context in desired component(s)
But I'm facing an issue with understanding the code block below
This is the solution to a file named ThemeContext.js.
import { createContext, useContext, useState } from "react";
const ThemeContext = createContext(undefined);
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider
value={{
theme,
toggleTheme: () => setTheme(theme === "light" ? "dark" : "light"),
}}
>
{children}
</ThemeContext.Provider>
);
};
export const useTheme = () => useContext(ThemeContext);
This is the solution to App.js.
import "./App.css";
import { ThemeProvider, useTheme } from "./ThemeContext";
import Switch from "./Switch";
const Title = ({ children }) => {
const { theme } = useTheme();
return (
<h2
style={{
color: theme === "light" ? "black" : "white",
}}
>
{children}
</h2>
);
};
const Paragraph = ({ children }) => {
const { theme } = useTheme();
return (
<p
style={{
color: theme === "light" ? "black" : "white",
}}
>
{children}
</p>
);
};
const Content = () => {
return (
<div>
<Paragraph>
We are a pizza loving family. And for years, I searched and searched and
searched for the perfect pizza dough recipe. I tried dozens, or more.
And while some were good, none of them were that recipe that would
make me stop trying all of the others.
</Paragraph>
</div>
);
};
const Header = () => {
return (
<header>
<Title>Little Lemon 🍕</Title>
<Switch />
</header>
);
};
const Page = () => {
return (
<div className="Page">
<Title>When it comes to dough</Title>
<Content />
</div>
);
};
function App() {
const { theme } = useTheme();
return (
<div
className="App"
style={{
backgroundColor: theme === "light" ? "white" : "black",
}}
>
<Header />
<Page />
</div>
);
}
function Root() {
return (
<ThemeProvider>
<App />
</ThemeProvider>
);
}
export default Root;
Finally, this is the solution to index.js
import "./Styles.css";
import { useTheme } from "../ThemeContext";
const Switch = () => {
const { theme, toggleTheme } = useTheme();
return (
<label className="switch">
<input
type="checkbox"
checked={theme === "light"}
onChange={toggleTheme}
/>
<span className="slider round" />
</label>
);
};
export default Switch;
My questions begin here
Instead of directly wrapping children with Provider, they instead create ThemeProvider that then returns ThemeContext.Provider. Why is this? and why is { children } necessary as seen in App.js along with the return ThemeContext return statement?
This exercise goes beyond what I believe was taught in the lesson, so I could have some holes to fill in my knowledge as far as using { children } along with the use of ThemeProvider. Normally it's demonstrated as <ThemeContext.Provider> wrapping children on the inside. In App it looks like they don't do this, but it's done in the Root, and maybe since they're wrapping App that's why { children } is indicated? I'm not certain about this and I'd just like to know why things were done specifically like this (again, this is unlike what was demonstrated in past exercises). First post, thanks in advance.
EDIT: After looking more into this issue I'm starting to come around and understand how they came up with this solution. One of the few things they didn't do previously that was used in this example was the use of ({ children }). This caused confusion for me at first, but I've come closer to understanding its usage. For example, its use in the Paragraph component:
const Paragraph = ({ children }) => {
const { theme } = useTheme();
return (
<p
style={{
color: theme === "light" ? "black" : "white",
}}
>
{children}
</p>
);
};
Which is later referenced in the Content component as such:
<Paragraph>
We are a pizza loving family. And for years, I searched and searched and
searched for the perfect pizza dough recipe. I tried dozens, or more.
And while some were good, none of them were that recipe that would
make me stop trying all of the others.
</Paragraph>
This simply means to take the children of the Paragraph component and return the information styled as such. Whatever comes inside of Paragraph, in this case a block of text, was returned with the intended style. I thought of deleting this post but maybe it will help someone else. Not sure if adding more about what I learned here would be excessive, and I'm still wrapping my head around the rest of the issue so documenting here isn't my top priority as of now.
React Context is a relatively new feature that the React team introduced to enable an alternative to holding state in a component and prop drilling. The context provider is a node that holds a value, which can be accessed by any node rendered under it (any children or children of children) via the createContext() with useContext or Context.Consumer. When the value of the Provider changes, any component subscribed with useContext or rendered by Consumer will be rerendered.
There is no practical difference between using the provider directly in index.js. What matters is who is rendered under the provider. Keep in mind that JSX's <ThemeProvider> is in reality a call to React.createElement with App in the children argument.
Why create a ThemeProvider? It packages the provider with state. The alternative would be to use the provider directly in Root and create useState there, but it is inflexible and not reusable.
const ThemeContext = createContext(undefined);
function Root() {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider
value={{
theme,
toggleTheme: () => setTheme(theme === "light" ? "dark" : "light"),
}}
>
<App />
</ThemeContext.Provider>
);
}
Note that App is still the children of the provider.

react typescript stitches css prop problem, not work

i'm currently working on a project using stitches with cra but i've stuck to a problem with css props.
here's my code
Texts/index.tsx
import React from 'react';
import { TextStyle } from './textStyle';
const Texts = ({ text, css }: PropsType) => {
console.log(css);
return (
<>
<TextStyle css={{ ...css }} >
<>{text}</>
</TextStyle>
</>
);
};
export default Texts;
and this index.tsx is exported to another components
Container/index.tsx
import { styled, css } from '../../../stitches.config';
// atoms
import Texts from 'src/components/atoms/texts';
const PageContainer = () => {
return (
<Container>
<Contents >
<div>
<Texts
css={{ color: 'red' }}
/>
<Texts
css={{ paddingTop: '20px' }}
/>
</div>
</Contents>
</Container>
);
};
export default PageContainer;
as you can see with the above code, contains css as its child but css is never rendered at all
can anyone help me with this issue?
FYI, console.log(css); returned undefined to me.
Thank you in advance!

Correct use of ReactToPrint?

The problem is that the button that is supposed to give the option to print is not working anymore.
the error in the console says:
To print a functional component ensure it is wrapped with `React.forwardRef`, and ensure the forwarded ref is used. See the README for an example: https://github.com/gregnb/react-to-print#examples
I Have already seen some solutions specifically talking about the same problem but I have not been able to make it work.
any suggestion?
this is the library i'm using: ReactToPrint npm
React To print
import { useRef } from "react";
import { useReactToPrint } from "react-to-print";
import Resume from "./Pdf/Pdf";
const Example = () => {
const componentRef = useRef();
const handlePrint = useReactToPrint({
content: () => componentRef.current
});
return (
<div >
<button onClick={handlePrint}> ------> NOT WORKING!
Descargar Pdf
</button>
<Resume ref={componentRef} /> ------> COMPONENT TO PRINT
</div>
);
};
export default Example;
Component to be printed
import React from "react";
import styled from 'styled-components';
import PdfSection from './PdfSection';
import AlienLevel from './AlienLevel';
import {connect } from 'react-redux';
class Resume extends React.Component {
renderList = () => {
return this.props.posts.diagnose.map((post) => {
return (
<PdfSection
key={post.id}
id={post.id}
divider={"/images/pdf/divider.png"}
img={"/images/alienRandom.png"}
title={post.title}
// data={post.data}
text={post.text0}
subtext={post.subtext0}
/>
);
});
};
render(){
return (
<div>
<Container>
<Page>
<Portada>
<img id="portada" src="/images/pdf/PortadaPdf.png" />
</Portada>
</Page>
<Page>
<AlienLevel
result= "{props.diagn}{"
character={"/images/pdf/alienMedio.png"}
fileName={"responseBody[4].data"}
level={"/images/pdf/level6.png"}
correct={"/images/pdf/correct.png"}
medium={"/images/pdf/medium.png"}
incorrect={"/images/pdf/incorrect.png"}
text='"Necesitas mejorar tus prácticas intergalácticas de CV, pero ya eres nivel medio!"'
/>
<div>{this.renderList()}</div>
</Page>
</Container>
</div>
);
};
}
const mapStateToProps = (state) => {
return { posts: state.posts };
};
export default connect(mapStateToProps)( Resume);
thanks in advance!
The problem is with connect() function of react-redux.
You wrapped your component in connect and connect by default does not forward ref. Which means, the ref you are passing here <Resume ref={componentRef} /> does not reach to your component.
You need to pass options { forwardRef: true } in fourth parameter of connect function connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?).
Just change this code export default connect(mapStateToProps)(Resume); in Resume component to this
export default connect(mapStateToProps, null, null, { forwardRef: true })(Resume);
For anyone that is struggling with the same error, it seems that they found the proper way to resolve this, I actually resolved it by following the Codesandbox I found in the Github issues here si the link. hope is useful! -->
LINK TO GITHUB SPECIFIC ISSUE (SOLVED!!)
I had the same issue and I am happy to share my findings as soon as now.
The component has to be rendered somewhere using ref.
I added it to my page as hidden using React Material UI's Backdrop. Or u can hide it using hooks like examples below.
Using backdrop and only calling it when I need to preview the print. 👇👇
<Backdrop sx={{ color: "#fff", zIndex: (theme) => theme.zIndex.drawer + 1 }}
open={openBD}>
<ComponentToPrint ref={componentRef} />
</Backdrop>
Using Hooks plus display styling to only display it when needed. 👇👇
const [isReady, setIsReady] = useState("none");
<Paper style={{ display: isReady }} >
<ComponentToPrint ref={componentRef} />
</Paper>
<Button
variant="contained"
endIcon={<BackupTableRoundedIcon />}
onClick={() => setIsReady("")}
>
Start Printing
</Button>
Note: I used MUI components, if u decide to copy paste, then change Button to html <button and paper to <div. Hope this helps.

React JS // Editing style of one component from another component

My goal is to create a basic app that allows me to change the style of one component with an action from another component.
Lets assume I have a <Btn/> component and a <Box/> component and when the button is clicked, I want to change the background color of the box. <Btn/> and <Box/> have the common ancestor of <App/> but are both at different levels in the component tree.
Btn.js
import React from 'react'
function Btn() {
const handleClick = (e) => {
//...
}
return (
<button onClick={handleClick}>
Click me
</button>
);
}
export default Btn
Box.js
import React from 'react'
function Box() {
return (
<h1>
Hello World!
</h1>
);
}
export default Box
I do not want to use prop drilling (with style setting/getting functionality in the <App/> component) to achieve this. I have also deliberately left out component styling as I am open to whichever styling option is best to solve this problem.
What would be the best way to go about this? (I'm open to using Context, Redux or another library if it is appropriate.)
The simplest way of doing this is with Context, as you're using function components not classes the documentation you'll need is useContext https://reactjs.org/docs/hooks-reference.html#usecontext. You still have to define the prop and "setter" function at the app level or at a component called at the app level, but with context you don't have to pass the props all the way down.
To take their example and adapt it to your use case would go something like this. (Working sample: https://codesandbox.io/s/stackoverflow-answer-7hryk)
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
};
const ThemeContext = React.createContext(themes.light);
function App() {
const [stateTheme, setTheme] = useState('light');
return (
<ThemeContext.Provider value={{ theme: themes[stateTheme], setTheme: setStateTheme }}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar(props) {
return (
<div>
<ToggleButtons />
<ThemedButton />
</div>
);
}
function ToggleButtons() {
const { setTheme } = useContext(ThemeContext);
return (
<div>
<button onClick={() => setTheme('light')}>Light Theme</button>
<button onClick={() => setTheme('dark')}>Dark Theme</button>
</div>
);
}
function ThemedButton() {
const { theme } = useContext(ThemeContext);
return (
<button style={{ background: theme.background, color: theme.foreground }}>
I am styled by theme context!
</button>
);
}

Passing styling options using JSS/Material-UI

I've written a small wrapper component for the Paper Material-UI Component:
import React from 'react';
import Paper from '#material-ui/core/Paper';
import {withStyles} from '#material-ui/core/styles';
const styles = theme => ({
root: {
...theme.mixins.gutters(),
paddingTop: theme.spacing.unit * 2,
paddingBottom: theme.spacing.unit * 2,
},
});
const PaddedPaper = (props) => {
const {classes, children} = props;
return (
<Paper className={classes.root}>
{children}
</Paper>
);
};
export default withStyles(styles)(PaddedPaper);
Which, as you may have guessed, is used like this:
<PaddedPaper>
<p>Some content.</p>
</PaddedPaper>
With JSS, is it possible to pass padding into PaddedPaper as a prop?
<PaddedPaper padding={20}>
<p>Some content.</p>
</PaddedPaper>
Since styles is defined outside of the PaddedPaper class, and doesn't have access to props, how can I pull this off? Or am I thinking about this entire process incorrectly?
When you're using withStyles, you have access to the theme, but not props.
this is still an ongoing issue : https://github.com/mui-org/material-ui/issues/7633
easiest way to use props in your styles is using inline styles (for now)
like this:
function PaperSheet(props) {
return (
<div>
<PaddedPaper {...props} size={10}>
<Typography variant="headline" component="h3">
This is a sheet of paper.
</Typography>
<Typography component="p">
Paper can be used to build surface or other elements for your
application.
</Typography>
</PaddedPaper>
</div>
);
}
const PaddedPaper = props => {
const { children, size } = props;
console.log(size);
return <Paper style={{ padding: size }}>{children}</Paper>;
};
here is a working example: https://codesandbox.io/s/yl4671wxz

Resources