I am using MUI Select for multi-select option and showing the final values after some modification as MUI Chips. Now when i click add the chip does not shows at that instant however If I change any value of name and suffix the page renders and then the chip shows. Maybe i am missing something. Any help is appreciated.
import { useState, } from 'react';
import styled from 'styled-components';
import {OutlinedInput, MenuItem, Chip, useTheme, Select} from '@mui/material';
const ITEM_HEIGHT = 48;
const ITEM_PADDING_TOP = 8;
const MenuProps = {
PaperProps: {
style: {
maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP,
width: 250,
},
},
};
const EditUser =styled.div`
display: flex;
align-items: center;
justify-content: flex-start;
margin-left:5px;
margin-top: 10px;
margin-bottom: 20px;
`
const Label = styled.label`
width: 100px;
margin: 10px;
`
const LabelInputWrapper = styled.div`
margin-bottom:25px;
flex:1 0 30%;
display: ${(props) => props.disp};
`
const Adduserformcont = styled.div`
display: flex;
flex-wrap:wrap;
margin:10px;
`
const AddChrgWrapper = styled.div`
display: flex;
`
const names = [
'Oliver Hansen',
'Van Henry',
'April Tucker',
'Ralph Hubbard',
'Omar Alexander',
'Carlos Abbott',
'Miriam Wagner',
'Bradley Wilkerson',
'Virginia Andrews',
'Kelly Snyder',
];
function getStyles(name, personName, theme) {
return {
fontWeight:
personName.indexOf(name) === -1
? theme.typography.fontWeightRegular
: theme.typography.fontWeightMedium,
};
}
const desigSuffix = ["I","II", "III", "IV"];
const EditUsers = () => {
const theme = useTheme();
const [personName, setPersonName] = useState([]);
const [value, setValue] = useState({})
const [finalValue, setFinalValue] =useState([])
const onChangeUserForm = (event) => {
if(event.target.name === 'selectMultiAddnCharg'){
setPersonName(event.target.value)
}
let temp = {...value, [event.target.name]:event.target.value}
setValue(temp);
console.log(temp)
}
const addWithSuffix = () => {
let tempArray = finalValue;
tempArray.push(`${value.adnCharge} (${value.desgnSuffix})`)
setFinalValue(tempArray)
}
return (
<>
<form>
<AddChrgWrapper>
<Label>Select name</Label>
<Select
name='selectMultiAddnCharg'
multiple
displayEmpty
value={personName}
onChange={onChangeUserForm}
input={<OutlinedInput />}
renderValue={(selected) => {
if (selected.length === 0) {
return <em>Select name</em>;
}
return selected.join(', ');
}}
MenuProps={MenuProps}
inputProps={{ 'aria-label': 'Without label' }}
>
<MenuItem disabled value="">
<em>Placeholder</em>
</MenuItem>
{names.map((name) => (
<MenuItem
key={name}
value={name}
style={getStyles(name, personName, theme)}
>
{name}
</MenuItem>
))}
</Select>
</AddChrgWrapper>
<LabelInputWrapper name="adnCharge">
<Label>Name</Label>
<select name="adnCharge" onChange={onChangeUserForm}>
<option>Select</option>
{personName.map((item,index) => <option key={index}>{item}</option>)}
</select>
</LabelInputWrapper>
<LabelInputWrapper name="desgnSuffix" >
<Label>Suffix</Label>
<select name="desgnSuffix" onChange={onChangeUserForm}>
<option>Select</option>
{desigSuffix.map((item,index) => <option key={index}>{item}</option>)}
</select>
</LabelInputWrapper>
<button type="button" onClick={(e)=>addWithSuffix(e)}>Add</button>
<div>{finalValue.map((item, index)=><Chip key={index} label={item}/>)}</div>
</form>
</>
)
}
export default EditUsers
In addWithSuffix
function, When you declared tempArray
it's not a new array, but you still mutate the finalValue
state directly, and this's not allowd.
From React docs:
state is a reference to the component state at the time the change is being applied. It should not be directly mutated. Instead, changes should be represented by building a new object based on the input from state.
You can declare new array variable based on old state
let tempArray = [...finalValue]
or use first argument of setFinalValue
that is old state
const addWithSuffix = () => {
let tempArray = [...finalValue];
tempArray.push(`${value.adnCharge} (${value.desgnSuffix})`)
setFinalValue(tempArray)
}
OR
const addWithSuffix = () => {
setFinalValue(state => state.concat(`${value.adnCharge} (${value.desgnSuffix})`))
}
Demo:
const names = [
'Oliver Hansen',
'Van Henry',
'April Tucker',
'Ralph Hubbard',
'Omar Alexander',
'Carlos Abbott',
'Miriam Wagner',
'Bradley Wilkerson',
'Virginia Andrews',
'Kelly Snyder',
];
function getStyles(name, personName, theme) {
return {
fontWeight:
personName.indexOf(name) === -1
? theme.typography.fontWeightRegular
: theme.typography.fontWeightMedium,
};
}
const desigSuffix = ["I","II", "III", "IV"];
const EditUsers = () => {
const { useState } = React
const { OutlinedInput, MenuItem, Chip, useTheme, Select } = MaterialUI;
const theme = useTheme();
const [personName, setPersonName] = useState([]);
const [value, setValue] = useState({})
const [finalValue, setFinalValue] =useState([])
const onChangeUserForm = (event) => {
if(event.target.name === 'selectMultiAddnCharg'){
setPersonName(event.target.value)
}
let temp = {...value, [event.target.name]:event.target.value}
setValue(temp);
console.log(temp)
}
const addWithSuffix = () => {
// let tempArray = finalValue;
const newVal = `${value.adnCharge} (${value.desgnSuffix})`
// tempArray.push(newVal)
setFinalValue(state => state.concat(newVal))
}
return (
<>
<form>
<div>
<label>Select name</label>
<Select
name='selectMultiAddnCharg'
multiple
displayEmpty
value={personName}
onChange={onChangeUserForm}
input={<OutlinedInput />}
renderValue={(selected) => {
if (selected.length === 0) {
return <em>Select name</em>;
}
return selected.join(', ');
}}
inputProps={{ 'aria-label': 'Without label' }}
>
<MenuItem disabled value="">
<em>Placeholder</em>
</MenuItem>
{names.map((name) => (
<MenuItem
key={name}
value={name}
style={getStyles(name, personName, theme)}
>
{name}
</MenuItem>
))}
</Select>
</div>
<div name="adnCharge">
<label>Name</label>
<select name="adnCharge" onChange={onChangeUserForm}>
<option>Select</option>
{personName.map((item,index) => <option key={index}>{item}</option>)}
</select>
</div>
<div name="desgnSuffix" >
<label>Suffix</label>
<select name="desgnSuffix" onChange={onChangeUserForm}>
<option>Select</option>
{desigSuffix.map((item,index) => <option key={index}>{item}</option>)}
</select>
</div>
<button type="button" onClick={(e)=>addWithSuffix(e)}>Add</button>
<div>{finalValue.map((item, index)=><Chip key={index} label={item}/>)}</div>
</form>
</>
)
}
const container = document.getElementById('root');
const root = ReactDOM.createRoot(container);
root.render(<EditUsers />);
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="https://unpkg.com/@mui/material@latest/umd/material-ui.production.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel" src="./script.js"></script>
</body>
</html>