How do you use Pseudo-classes in React using css modules? - reactjs

The example I worked on is the following:
I have a button component that receives the background color as props. The received color will be the background that the button must have when hovering.
Second question:
The only way to use props in css, using css modules, is to apply the inline style in the js file where you declare the component?
Below I insert a code base (in the example the background color is applied by default):
import Button from "./Button";
export default function App() {
return <Button hoverColor={"red"} />;
}
...
export default function Button({ hoverColor }) {
const buttonStyle = {
backgroundColor: hoverColor
};
return <button style={buttonStyle}>click me!</button>;
}
Thanks

You may use React useState Hook to achieve the desired functionality: (Your Button component should look like this)
import React, { useState } from "react";
export default function Button({ hoverColor }) {
const [color, setColor] = useState("");
const buttonStyle = {
backgroundColor: color
};
return (
<button
style={buttonStyle}
onMouseOver={() => setColor(hoverColor)} //set the color when user hovers over the button
onMouseOut={() => setColor("")} //set color to an empty string otherwise
>
click me!
</button>
);
}

Related

Rendered Component doesn't show in storybook

I want to render MUI Button Component in my storybook and then change MUI attributes(variant, color, disabled, etc.) from storybook. I could get result when working on simple plain html button but it doesn't work on MUI one. The current result is it doesn't show any error in terminal, nor in browser. When I type something in args it's visible on Storybook Controls but Button itself doesn't show up itself. Here is the code of MyNewButton.tsx file.
import Button from "#mui/material/Button"
export const MyNewButton = () => {
return <Button />
}
and here is the code of MyNewButton.stories.tsx
import { ComponentMeta, ComponentStory } from "#storybook/react"
import { MyNewButton } from "./MyNewButton"
export default {
title: "MyComponents/MyNewButton",
component: MyNewButton,
} as ComponentMeta<typeof MyNewButton>
const Template: ComponentStory<typeof MyNewButton> = (args) => (
<MyNewButton {...args} />
)
export const First = Template.bind({})
First.args = {
label: "MyNewButton",
backgroundColor: "red",
}
and Here is the storybook screenshot.
So, I can see you are overlooking some basic steps and I'm going to point them out to you. Your Storybook is rendering fine.
First, you are rendering a button from MUI without a label/text. You are supposed to have an opening tag and a closing tag for the button.
so, it should be <Button>Hello World!</Button> and not <Button />.
After fixing that, the next step is to use your args in your MyNewButton component so that storybook will know what to change your background color to.
import { FC } from "react";
type ButtonProps = {
backgroundColor: string;
label: string;
};
export const MyNewButton: FC<ButtonProps> = (props) => {
const { backgroundColor, label } = props;
const style = {
backgroundColor,
};
return (
<Button variant="contained" style={style}>
{label}
</Button>
);
};
Your button should be rendering fine correctly now and to make change the background in your app, you just have to pass in the props like so:
<MyNewButton backgroundColor={"green"} label={"My New Button"} />

How to use array method to change different color on div in. In single button reactjs click

import { use state } from 'react';
import React from 'react';
import './style.css';
export default function Div() {
const [data, set data] = useState('green');
return (
<div class="sec" style={{ 'background-color': data }}>
{data}
<button on Click={() => setData('red', 'orange')}>state click
);
}
First => You should remove the space between the words "set" and "data" like this:
const [data, setData] = useState('green');
Second => in the style attribute just the second argument is a string, but in this case you will have to use "Template literals" using backticks(`) like this:
<div class="sec" style={{ background-color: `${data}`}}>
I've fixed the typos and errors in your code, and it seems to be working fine.
import { useState } from "react";
import React from "react";
import "./style.css";
export default function Div() {
const [data, setData] = useState("green");
return (
<div class="sec" style={{ "background-color": data }}>
<button onClick={() => setData("orange")}>state click</button>
</div>
);
}
it changes the background color to orange when the button is clicked, but I still don't understand, do you want to change the color of the background based on an array of colors? if so you can do it using the Math.random, on each click a random item from the colors array will be generated.
import { useState } from "react";
import React from "react";
import "./style.css";
export default function Div() {
const [data, setData] = useState("green");
const handleColorChange = () => {
const colors = ["orange", "green", "red", "black"];
var colorItem = colors[Math.floor(Math.random() * colors.length)];
setData(colorItem);
};
return (
<div class="sec" style={{ "background-color": data }}>
<button onClick={() => handleColorChange}>state click</button>
</div>
);
}
Here is short explanation
First: The state is used to store things which change.
The array of colours isn't going to change, so don't store it in the state.
The selected colour is going to change, so do store that in the state. In this case, you can do that by using the index of the colour in the array.
Next, when the colour changes, you want to pick the next one. That's just a matter of incrementing the index. However, when you get to the end you'll probably want to loop back. So check for that.
Third, since you only want one button, create only one button. Don't loop over the array of colours there.
Use the value from the state to assign the background colour.
onclick is onClick in React.
Just pass the function for setting the nextColour. It doesn't need any arguments.
Finally, if you want an HTML button element then it is . Starting a JSX name with a capital letter means you are using a component. There are plenty of third-party Button components, but you aren't importing any. Trying to use here would be recursively using the component you just created.
import React, { useState } from "react";
const colours = ['red', 'green', 'blue', 'orange', 'yellow'];
export function Button(props) {
const [selectedColourIndex, setColourIndex] = useState(0);
const nextColour = () => {
const newColourIndex = selectedColourIndex + 1;
if (colours[newColourIndex])
setColourIndex(newColourIndex);
else
setColourIndex(0);
}
return (<button type="button" style={{backgroundColor: colours[selectedColourIndex]}}
onClick={nextColour}>Change color</button>);
}

How to pass ref const from parent to child component in react functional component?

I am working on the Reactjs project and I want to open a dialog box which is a global component from a cart page.
This is cart page when I click on cart delete button then it shows dialog current is null.
/**
* Cart Page
*/
import React, { Fragment } from 'react';
import { Button,Box} from '#material-ui/core';
import { ConfirmationDialog } from 'components/GlobalComponents';
import IntlMessages from 'util/IntlMessages';
function Cart(props){
const [anchorEl,setAnchorEl] = React.useState(null);
const [item,setItem] = React.useState('');
const dialog = React.useRef(null);
const onDeleteCartItem = (item) => {
// setItem(item);
console.log(dialog);
// dialog.current.open();
}
const deleteCartItem = (popupResponse) => {
console.log(popupResponse);
}
return (
<div className="cart-page white-btn-color">
<Button
className="cart-delete"
onClick={() => onDeleteCartItem(cart)}
>
<Box component="span" className="material-icons-outlined">delete</Box>
</Button>
<ConfirmationDialog
ref={dialog}
onConfirm={(res) => deleteCartItem(res)}
/>
</div>
)
}
export default Cart;
Confirmation Dialog:
import React from 'react';
import { Dialog, DialogContent, DialogActions, Button, Box, Typography } from '#material-ui/core';
function ConfirmationDialog(props) {
const [open,setOpen] = React.useState(false);
//Define function for open confirmation dialog box
const openDialog = () => {
setOpen(true);
};
//Define function for close confirmation dialog box and callback for delete item
const closeDialog = (isTrue) => {
setOpen(false);
props.onConfirm(isTrue)
};
console.log(props);
return (
<Dialog
open={open}
ref={props.ref}
onClose={()=>closeDialog()}
aria-labelledby="responsive-dialog-title"
>
<DialogContent>
<Box textAlign="center" pt={2}>
<Typography variant="h5">
Are you sure you want to delete this product ?
</Typography>
</Box>
</DialogContent>
</Dialog >
);
}
export { ConfirmationDialog };
I am trying with the above-mentioned code this is not working please tell me where I`m wrong.
Thanks
There are a few things going wrong. Firstly, the ref prop has a special meaning and is not passed to the component unless you use React.forwardRef().
Then, according to the docs you should not use ref as a means to expose an API, so to speak.
My preferred method is to define the dialog way up in the component tree and expose the open/close functions via a context. You can consume those methods with useContext() or even create your own useDialog() which internally calls useContext() (in the file that declares the dialog) with the local context object, so you don't have to export the context object.

Changing button label on click with grommet?

Does anyone have any insight into changing button label on click when using grommet UI and styled components? Is it easier to just use a custom button rather than grommets?
Here are a few examples on how to make the Button label change onClick action:
import React, { useState } from "react";
import { render } from "react-dom";
import { grommet, Box, Button, Grommet, Text } from "grommet";
const App = () => {
const [label, setLabel] = useState(1);
const [name, setName] = useState("shimi");
const flipName = name => {
return name === "shimi" ? setName("shai") : setName("shimi");
};
return (
<Grommet theme={grommet}>
<Box pad="small" gap="small" width="small">
// label is a number that is being increased on every click event
<Button
label={label}
onClick={() => {
setLabel(label + 1);
}}
/>
// label string is controlled with external logic outside of the button.
<Button
label={<Text weight="400">{name}</Text>}
onClick={() => {
flipName(name);
}}
/>
</Box>
</Grommet>
);
};
render(<App />, document.getElementById("root"));
In addition to the examples above, in Grommet, you don't have to use the label prop and you can leverage the Button children to control the way your Button display.

How to reuse a Custom Material-ui button inside a react-app?

I'm developing my first React app. I've imported a Material-ui button and I've customized it.
Now I want to reuse this custom button in several components of my app. I want a different text for each time I use this custom button.
Where do I need to write this specific text for each button?
My button is visible when I import it in other components, but I can't see the text I wrote inside the button component. The button stays empty.
My custom button component : MyButton:
import React from "react";
import Button from "#material-ui/core/Button";
import { withStyles } from "#material-ui/core/styles";
const styles = () => ({
button: {
margin: 50,
padding: 10,
width: 180,
fontSize: 20
}
});
function MyButton(props) {
const { classes } = props;
return (
<Button variant="contained" color="primary" className={classes.button}>
<b> </b>
</Button>
);
}
export default withStyles(styles)(MyButton);
The other component where I import MyButton component : Home :
import React from "react";
import "../App.css";
import MyButton from "./Button";
function Header() {
return (
<header className="Header">
{/* background image in css file */}
<h1>Welcome </h1>
<h3> description...</h3>
<MyButton>Play now</MyButton>
</header>
);
}
export default Header;
I expect the button to show "Play now" (expected output) but for now it stays empty (actual output).
Also, I've found another solution that offers the possibility to write directly the text inside each button (children of MyButton), and customize it if needed.
Pass "children" keyword as "props" to MyButton component :
function MyButton(props) {
const { classes, children } = props;
return (
<Button variant="contained" color="primary" className={classes.button}>
<b>{children}</b>
</Button>
);
}
Then write the text of your button inside the button as you will do in html :
<MyButton> Play now </MyButton>
You will get the most flexibility from your custom Button if you pass all of the props along to the wrapped Button. This will automatically take care of children and classes so long as you use class keys in your styles object that match the CSS classes supported for the wrapped component.
import React from "react";
import Button from "#material-ui/core/Button";
import { withStyles } from "#material-ui/core/styles";
const styles = () => ({
root: {
margin: 50,
padding: 10,
width: 180,
fontSize: 20,
fontWeight: "bold"
}
});
function CustomButton(props) {
return <Button variant="contained" color="primary" {...props} />;
}
export default withStyles(styles)(CustomButton);
Notice in the sandbox example, that this allows you to still leverage other Button features like disabled, specify additional styles, or override some properties specified in CustomButton.
If you have a scenario where you need to handle children explicitly (in my example above I used fontWeight CSS instead of the <b> tag), you can use the following syntax to still pass all the props through to the wrapped component:
function CustomButton({children, ...other}) {
return <Button variant="contained" color="primary" {...other}><b>{children}</b></Button>;
}
Pass text of button as props to your button component
<MyButton text="Play now"></MyButton>
Then inside MyButton component you can get it like
function MyButton(props) {
const { classes,text } = props;
return (
<Button variant="contained" color="primary" className={classes.button}>
<b> {text} </b>
</Button>
);
}

Resources