I have ButtonRegistration component where I implemented a work after pressing on the button Registration. When the user presses on the button the modal with input fields appear and the user can types his data(name, email, password, confirmPassword)
const ButtonRegistration = () => {
const dispatch = useDispatch();
const user = useSelector((state) => state.user);
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down("md"));
const [open, setOpen] = useState(false);
const [error, setError] = useState(user.errorMessage);
/*Handler for Sign UP section*/
const handleSignup = () => {
dispatch(valideteNewUser(user));
};
/*Handlers for Button-Dialog section*/
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
/*Handler for Modal section*/
const handleCloseErrorMessage = () => {
setError(null);
};
return (
<div style={{ marginLeft: "1rem" }}>
{/*section Button-Dialog*/}
<Button
onClick={handleClickOpen}
variant="outlined"
size="small"
sx={{ background: "rgb(177, 209, 227);" }}
>
Registration
</Button>
<Dialog
fullScreen={fullScreen}
open={open}
onClose={handleClose}
PaperProps={{
component: "form",
onSubmit: (event) => {
event.preventDefault();
const formData = new FormData(event.currentTarget);
const formJson = Object.fromEntries(formData.entries());
const email = formJson.email;
console.log(email);
handleClose();
},
}}
></Dialog>
{/*section Modal*/}
<Modal
aria-labelledby="modal-title"
aria-describedby="modal-desc"
open={open}
onClose={() => setOpen(false)}
sx={{
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<Sheet
variant="outlined"
sx={{
maxWidth: 500,
borderRadius: "md",
p: 3,
boxShadow: "lg",
}}
>
<ModalClose
variant="plain"
sx={{ m: 1 }}
onClick={handleCloseErrorMessage}
/>
<Typography
component="h2"
id="modal-title"
level="h4"
textColor="inherit"
fontWeight="lg"
mb={1}
>
Registration
</Typography>
{/*section Sign UP*/}
<Box
>
<Input
size="lg"
value={user.name}
onChange={(e) => dispatch(setName(e.target.value))}
type="text"
placeholder="Enter your name..."
></Input>
<Input
size="lg"
value={user.email}
onChange={(e) => dispatch(setEmail(e.target.value))}
type="text"
placeholder="Enter email..."
></Input>
<Input
size="lg"
value={user.password}
onChange={(e) => dispatch(setPassword(e.target.value))}
type="password"
placeholder="Enter password..."
></Input>
<Input
size="lg"
value={user.confirmdPassword}
onChange={(e) => dispatch(setConfirmPassword(e.target.value))}
type="password"
placeholder="Confirm password..."
></Input>
<Button size="md" onClick={handleSignup}>
Register
</Button>
{error && (
<Typography variant="body2" color="error">
{error}
</Typography>
)}
</Box>
</Sheet>
</Modal>
</div>
);
};
export default ButtonRegistration;
When the user typed incorrect data which I check by using Joi:
const Joi = require("joi");
const validator = (scheme) => (payload) =>
scheme.validate(payload, { abortEarly: false });
const signupSchema = Joi.object({
name: Joi.string().required(),
email: Joi.string().email({ tlds: { allow: false } }).required(),
password: Joi.string().min(3).max(10).required(),
confirmPassword: Joi.ref("password"),
});
exports.validateRegister = validator(signupSchema);
I tried to render the message about incorrectly entered data by usin variable error in ButtonRegistartion component. I have the following action and reducer:
Action
export const valideteNewUser = (name, email, password, confirmPassword) => ({
type: VALIDATE_USER,
payload: {
name,
email,
password,
confirmPassword,
},
});
export const setName = (name) => ({
type: SET_NAME,
payload: name,
});
export const setEmail = (email) => ({
type: SET_EMAIL,
payload: email,
});
export const setPassword = (password) => ({
type: SET_PASSWORD,
payload: password,
});
export const setConfirmPassword = (confirmPassword) => ({
type: SET_CONFIRM_PASSWORD,
payload: confirmPassword,
});
export const setErrorMessage = (errorMessage) => ({
type: ERROR_MESSAGE,
payload: errorMessage,
});
Reducer:
export const initialState = {
user: {
name: "",
email: "",
password: "",
confirmdPassword: "",
errorMessage: null,
},
};
export function userReducer(state = initialState, action) {
switch (action.type) {
case VALIDATE_USER:
const { error } = validateRegister({
name: action.payload.name,
email: action.payload.email,
password: action.payload.password,
confirmPassword: action.payload.confirmPassword,
});
if (error) {
return {
...state,
errorMessage: error.details.map((d) => d.message).join(", "),
};
} else {
return {
...state,
errorMessage: null,
};
}
case SET_NAME:
return {
...state,
user: {
...state.user,
name: action.payload,
},
};
case SET_EMAIL:
return {
...state,
user: {
...state.user,
email: action.payload,
},
};
case SET_PASSWORD:
return {
...state,
user: {
...state.user,
password: action.payload,
},
};
case SET_CONFIRM_PASSWORD:
return {
...state,
user: {
...state.user,
confirmPassword: action.payload,
},
};
case ERROR_MESSAGE:
return {
...state,
user: {
...state.user,
errorMessage: action.payload,
},
};
default:
return state;
}
}
When the user types incorrect data then nothing appears but in the same moment I see in my Redux devTools that my errrorMessage changes.
How can implement the render of incorrectly inputs. Thanks in advance?
The ButtonRegistration
incorrectly duplicates the selected user.errorMessage
state into local state. This is a React anti-pattern. The basic gist is that the local error
state doesn't update when the user.errorMessage
value from the store updates.
Update the ButtonRegistration
component to reference and update the user.errorMessage
state directly.
const ButtonRegistration = () => {
const dispatch = useDispatch();
const user = useSelector((state) => state.user); // <-- includes errorMessage
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down("md"));
const [open, setOpen] = useState(false);
/*Handler for Sign UP section*/
const handleSignup = () => {
dispatch(validateNewUser(user)); // <-- updates user.errorMessage
};
...
/*Handler for Modal section*/
const handleCloseErrorMessage = () => {
dispatch(setErrorMessage(null)); // <-- clear user.errorMessage state
};
return (
<div ... >
...
<Modal ... >
<Sheet ... >
...
<Box>
...
{user.errorMessage && (
<Typography variant="body2" color="error">
{user.errorMessage}
</Typography>
)}
</Box>
</Sheet>
</Modal>
</div>
);
};
export default ButtonRegistration;