React component is not re-rendering multiple time - javascript

I am making an application in which i have a button which change the theme from dark to light of the component. my application works fine for the first time but it does not work on second attempt
for example : If i click the button first time then it will change the theme to the dark mode but when i want to change the theme into light mode then it does not work
import {
Button,
createMuiTheme,
Grid,
Paper,
Switch,
ThemeProvider,
Typography,
} from "#material-ui/core";
import React, { Component } from "react";
export default class Mode extends Component {
constructor(props) {
super(props);
this.state = {
switch: false,
};
this.darkTheme = createMuiTheme({
palette: {
type: "dark",
},
});
this.lightTheme = createMuiTheme({
palette: {
type: "light",
},
});
}
componentDidUpdate() {
console.log(this.state.switch);
}
render() {
return (
<div>
<ThemeProvider
theme={this.state.switch === true ? this.darkTheme : this.lightTheme}
> // <-- **Condition for changing the mode**
<Paper style={{ height: "100vh" }}>
<Grid container direction="column">
<Typography variant="h1">this is my app</Typography>
<Button variant="contained" color="primary">
A button
</Button>
<Button variant="contained" color="secondary">
Another button
</Button>
<Switch
checked={this.state.switch}
onChange={() =>
this.setState((prev) => ({ switch: !prev.switch }))
}
name="Dark Mode"
inputProps={{ "aria-label": "secondary checkbox" }}
/>
</Grid>
</Paper>
</ThemeProvider>
</div>
);
}
}
I am using material ui for this

I'm not sure why it changes only one time. But you can fix by create theme every render.
First, create function createTheme:
const createTheme = (isDark) =>
createMuiTheme({
palette: {
type: isDark ? "dark" : "light",
},
});
Then, update ThemeProvider like this:
<ThemeProvider theme={createTheme(this.state.switch)}>

Related

Warning: Each child in a list should have a unique "key" prop. how to fix this?

Ive been using this project with out a problem and now all of a sudden I keep getting this error and it won't show my notes when I click on the my notes section. What do I have to do for it to go away. The backend is up and running and I can see the static data but it wont show on the app
import { makeStyles } from '#mui/styles'
import React from 'react'
import { Drawer } from '#mui/material'
import { Typography } from '#mui/material'
import List from '#mui/material/List'
import ListItem from '#mui/material/ListItem'
import ListItemIcon from '#mui/material/ListItemIcon'
import ListItemText from '#mui/material/ListItemText'
import { AddCircleOutlineOutlined, SubjectOutlined } from '#mui/icons-material'
import { useHistory, useLocation } from 'react-router-dom'
import AppBar from '#mui/material/AppBar'
import Toolbar from '#mui/material/Toolbar'
import { format } from 'date-fns'
import { red } from '#mui/material/colors'
const drawerWidth = 240 // 500 - subtract this number from
const useStyles = makeStyles((theme) => {
return{
page: {
background: '#E5E4E2',
width: '100%',
padding: theme.spacing(3)
},
drawer: {
width: drawerWidth
},
drawerPaper: {
width: drawerWidth
},
root: {
display: 'flex' //places the drawer side by side with the page content
},
active: {
background: '#E5E4E2'
},
// title:{
// padding: theme.spacing(13),
// alignItems: 'center'
// },
}})
export default function Layout({ children }) {
const classes = useStyles()
const history = useHistory()
const location = useLocation()
const menuItems = [
{
text: 'My Projects',
icon: <SubjectOutlined color="secondary" />,
path: '/'
},
{
text: 'Create Project',
icon: <AddCircleOutlineOutlined color="secondary" />,
path: '/create'
}
]
return (
<div className={classes.root}>
{/* side drawer */}
<Drawer
className={classes.drawer}
variant='permanent' //Lets MUI know we want it on the page permanently
anchor="left" // position of drawer
classes={{ paper: classes.drawerPaper}}
>
<div>
<Typography variant="h5" sx={{textAlign: 'center'}}>
Projects
</Typography>
</div>
{/* List / Links */}
<List>
{menuItems.map(item => (
<div className={location.pathname == item.path ? classes.active : null}>
<ListItem key={item.text} button onClick={() => history.push(item.path)}>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.text} />
</ListItem>
</div>
))}
</List>
</Drawer>
<div className={classes.page}>
<div className={classes.toolbar}></div>
{children}
</div>
</div>
)
}
enter image description here
Updated
I'm sorry, of course, you should just move key to the parent div. I didn't notice it. Chris who answered in the comments is right and my answer was not needed. I rewrote the answer.
To have an unique key use index in map or like you did item.text if text is unique for each element in map.
menuItems.map((item,index) =>
The idea is that map has to contain unique key for each element.
In result we have:
<div key={item.text} className={location.pathname == item.path ? classes.active : null}>
or
<div key={index} className={location.pathname == item.path ? classes.active : null}>
And you need to remove key from the List.
Hope this helps! Regards,

when state is changed, ckeditor5 is rendered in duplicate in react

currently, i'm trying to create on/Off function to appear or disappear Ckeditor5
below my code
import { Box, Button, styled, Typography } from "#mui/material";
import React from "react";
import { CKEditor } from "#ckeditor/ckeditor5-react";
import ClassicEditor from "#ckeditor/ckeditor5-build-classic";
const Description = ({ description }) => {
const [isEdit, setIsEdit] = React.useState(false);
const handlerOnOff = () => {
setIsEdit((prev) => !prev);
};
return (
<Root>
<Box>
<Typography component="span">Description</Typography>
<Button onClick={handlerOnOff}>Edit</Button>
</Box>
<Box>
{isEdit ? (
<div>
<CKEditor
config={{
toolbar: [
"heading",
"|",
"bold",
"italic",
"bulletedList",
"numberedList",
"blockQuote"
]
}}
data={description}
editor={ClassicEditor}
/>
</div>
) : (
<>{description}</>
)}
</Box>
</Root>
);
};
const Root = styled("div")(({ theme }) => ({
marginBottom: "60px",
"& .ck-content": {
minHeight: "200px"
}
}));
export default Description;
and codesandbox
https://codesandbox.io/embed/suspicious-mahavira-eoeip1?fontsize=14&hidenavigation=1&theme=dark
when click button named Edit and changed true of state name isEdit, Ckeditor is rendered in duplicate

React Failed to customise Material UI button

I was using this package material UI for a project. The version is rather old(v1) as I need it to be compatible to the project itself(using node 10.8)
Right now I am trying to use a round button (see this demo) I was trying to use a round mini button, it worked pretty well when I am not using any theme.
<Button
id={this.props.id}
variant="fab" mini
onClick={this.props.onClick}
color={this.state.clicked ? "primary" : 'default' }>
{sth}
</Button>
Then I was trying to change the colour of the button. I added a theme and use that theme to wrap on the button.
This is not the first time I did such thing, as I changed the colour for a number of buttons before by doing this(they're all rectangular contained buttons).
const confirm_theme = createMuiTheme({
palette: {
primary: {
main: '#006D8F',
contrastText: '#fff',
},
},
});
export class StyledButton extends Component {
constructor(props) {
super(props);
this.state = {
clicked: false,
};
}
handleClick = (e) => {
this.setState({ clicked: !this.state.clicked });
}
render(){
return (
<Row
style={{ paddingTop: 10, justifyContent: "center"}}>
<MuiThemeProvider theme={confirm_theme}>
<Button
variant="contained"
id={this.props.id}
onClick={this.props.onClick}
color={this.state.clicked ? 'default' : "primary"}>
{sth}
</Button>
</MuiThemeProvider>
</Row>
)
}
}
However, this time I failed to do so, when I use it on a round mini button.
There were no error messages, and the colour of the button has been changed successfully, but the button went blank.
Has anyone encountered something like this? Is it possible to fix?(I know my version is quite old, so I understand there might not be a solution)
Your handleClick function is never triggered.
So instead of passing this.props.onClick to the button component you can pass the handleClick function and then call your this.props.onClick function inside the handleClick.
const confirm_theme = createMuiTheme({
palette: {
primary: {
main: '#006D8F',
contrastText: '#fff',
},
},
});
export class StyledButton extends Component {
constructor(props) {
super(props);
this.state = {
clicked: false,
};
}
handleClick = (e) => {
this.setState({ clicked: !this.state.clicked });
this.props.onClick();
}
render(){
return (
<Row
style={{ paddingTop: 10, justifyContent: "center"}}>
<MuiThemeProvider theme={confirm_theme}>
<Button
variant="contained"
id={this.props.id}
onClick={this.handleClick}
color={this.state.clicked ? 'default' : "primary"}>
{sth}
</Button>
</MuiThemeProvider>
</Row>
)
}
}
Live demo:

How to change material-ui Textfield label styles in react

I'm new to Material-UI, I couldn't able to figure it out, how to change the color of the label which is showing in grey color. I want it in black. Can anyone help me with this query?
Here is the Code :
import React from "react";
import ReactDOM from "react-dom";
import { TextField, Button, Grid } from "#material-ui/core";
class App extends React.Component {
render() {
return (
<Grid container justify={"center"} alignItems={"center"} spacing={1}>
<Grid item>
<TextField
id="outlined-name"
label="Name"
value={"Enter value"}
onChange={() => console.log("I was changed")}
margin="normal"
variant="outlined"
/>
</Grid>
<Grid item>
<Button variant="contained" color="primary">
Submit
</Button>
</Grid>
</Grid>
);
}
}
Here is the code: "https://codesandbox.io/s/fancy-morning-30owz"
If you use the selection tools in your browser, you would find out that:
The class name used is MuiFormLabel-root
<label class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-outlined MuiFormLabel-filled" data-shrink="true" for="outlined-name">Name</label>
So set the styles using nesting selector to the TextField component
Functional component
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles(theme => ({
root: {
"& .MuiFormLabel-root": {
color: "red" // or black
}
}
}));
...
const classes = useStyles();
Classical component
import { withStyles, createStyles } from "#material-ui/core/styles";
const styles = theme => createStyles({
root: {
"& .MuiFormLabel-root": {
color: "red"
}
}
});
...
const { classes } = this.props;
...
export default withStyles(styles)(App);
usage
<TextField
className={classes.root}
...
>
</TextField>
By this way, you can change the label color, as the screenshot is shown below (currently red)
Try it online:
If you want to leave your style in a separate file, you can write:
.MuiTextField-root > label {
background-color: $bg-color;
color: $color;
}
.MuiTextField-root > .MuiFormLabel-root.Mui-focused {
color: $color;
}

How to assign which MenuItems open onClick when multiple Menus are present on the material-ui Appbar using React?

I created an AppBar with a menu based on the examples given on the material UI site and it works fine with one menu. But when I try adding a second dropdown menu, on clicking either icon, I get the same set of MenuItems showing up as seen in the image.
Here is the list of menu items that are showing up when either icon is clicked
import React, { Component } from 'react';
// Material UI Imports
import { withStyles } from 'material-ui/styles';
import AppBar from 'material-ui/AppBar';
import Toolbar from 'material-ui/Toolbar';
import Typography from 'material-ui/Typography';
import Button from 'material-ui/Button';
import IconButton from 'material-ui/IconButton';
import Tooltip from 'material-ui/Tooltip';
import Menu, { MenuItem } from 'material-ui/Menu';
import PeopleIcon from 'material-ui-icons/People';
import ViewListIcon from 'material-ui-icons/ViewList';
import CompareArrowsIcon from 'material-ui-icons/CompareArrows';
const styles = {
root: {
width: '100%',
},
flex: {
flex: 1,
},
menuItem: {
paddingLeft: '10px'
}
}
class Header extends Component {
constructor(props) {
super(props);
this.state = { anchorEl: null };
}
handleMenu = event => {
console.log(event.currentTarget);
this.setState({ anchorEl: event.currentTarget });
}
handleClose = () => {
this.setState({ anchorEl: null });
}
render() {
const { classes } = this.props;
const { anchorEl } = this.state;
const open = Boolean(anchorEl);
return(
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<Typography type="title" color="inherit" className={classes.flex}>
New Faces
</Typography>
{/* Menu Item One */}
<div>
<Tooltip title="Lists" className={classes.menuItem}>
<IconButton
color="inherit"
aria-owns={open ? 'menu-list' : null}
aria-haspopup="true"
onClick={this.handleMenu}
>
<ViewListIcon />
</IconButton>
</Tooltip>
<Menu
id="menu-list"
anchorEl={anchorEl}
anchorOrigin={{
vertical: 'top',
horizontal:'right',
}}
transformOrigin={{
vertical: 'top',
horizontal:'right',
}}
open={open}
onClose={this.handleClose}
>
<MenuItem onClick={this.handleClose}>Create List</MenuItem>
<MenuItem onClick={this.handleClose}>List 1</MenuItem>
<MenuItem onClick={this.handleClose}>List 2</MenuItem>
</Menu>
</div>
{/* Menu Item Two */}
<div>
<Tooltip title="User Management" className={classes.menuItem}>
<IconButton
color="inherit"
aria-owns={open ? 'menu-appbar' : null}
aria-haspopup="true"
onClick={this.handleMenu}
>
<PeopleIcon />
</IconButton>
</Tooltip>
<Menu
id="menu-appbar"
anchorEl={anchorEl}
anchorOrigin={{
vertical: 'top',
horizontal:'right',
}}
transformOrigin={{
vertical: 'top',
horizontal:'right',
}}
open={open}
onClose={this.handleClose}
>
<MenuItem onClick={this.handleClose}>Profile</MenuItem>
<MenuItem onClick={this.handleClose}>User Management</MenuItem>
<MenuItem onClick={this.handleClose}>Logout</MenuItem>
</Menu>
</div>
</Toolbar>
</AppBar>
</div>
);
}
}
export default withStyles(styles)(Header);
How do you assign which MenuItems show up according to the icon that is clicked? I assumed it was supposed to show the MenuItems that are directly under the selected anchorEl. Any help would be much appreciated!
Check this working solution https://codesandbox.io/s/84xl2v8wm2 I whipped up
What I have done is extract the common code into a separate component lets call it MenuButton and use it at multiple places. So that each menu button has its own scope, own event handlers etc. Currently, the issue is that you are using same event handlers for two different elements and using the same variable to keep track of the state of the menu. Either use two variables like open and open1 or extract the code into a separate component like I have done.
Parent file
<MenuButton iconType={AccountCircle} items={['Create','List1', 'List2']}/>
<MenuButton iconType={MenuIcon} items={['Profile','User Management', 'Logout']}/>
menuButton.js file
import React from 'react';
import AccountCircle from 'material-ui-icons/AccountCircle';
import Menu, { MenuItem } from 'material-ui/Menu';
import IconButton from 'material-ui/IconButton';
import { withStyles } from 'material-ui/styles';
class MenuButton extends React.Component {
state = {
anchorEl: null
};
handleChange = (event, checked) => {
this.setState({ auth: checked });
};
handleMenu = event => {
this.setState({ anchorEl: event.currentTarget });
};
handleClose = () => {
this.setState({ anchorEl: null });
};
render() {
const { classes } = this.props;
const { auth, anchorEl } = this.state;
const open = Boolean(anchorEl);
const Wrapper = this.props.iconType;
const listItems = this.props.items.map((link) =>
<MenuItem onClick={this.handleClose} >{link}</MenuItem>
);
return (
<div>
<IconButton
aria-owns={open ? 'menu-appbar' : null}
aria-haspopup="true"
onClick={this.handleMenu}
color="contrast"
>
{<Wrapper />}
</IconButton>
<Menu
id="menu-appbar"
anchorEl={anchorEl}
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={open}
onClose={this.handleClose}
>
{listItems}
</Menu>
</div>
);
}
}
export default MenuButton;

Categories

Resources