使用Material UI、Formik和Typescript设置表单值时出现的问题

huangapple go评论72阅读模式
英文:

Problems setting the values ​of a form using Material UI, Formik and Typescript

问题

I'm trying to set the 'role' and 'active' values on a form.

The first problem is that the original values of the selectors are not set, which are fetched in the ManageUserDialog Props, so when starting the component, the selectors are shown empty.

The second problem is that selecting one of the selector options doesn't set its value.

I attach images of the component, the code, and the error delivered by the console.

使用Material UI、Formik和Typescript设置表单值时出现的问题

使用Material UI、Formik和Typescript设置表单值时出现的问题

import {
    Button,
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    useMediaQuery,
    useTheme,
    Grid,
    TextField,
    MenuItem
} from '@mui/material';
import { Formik } from "formik";
import * as yup from 'yup';
import * as UsersApi from '../network/UsersApi';
import { useGlobalState } from '../context/hookStateProvider';


interface ManageUserFormInterface {
    role: number;
    active : boolean;
}

const ManageUserSchema = yup.object().shape({
    role: yup.number().required("Required"),
    active: yup.boolean().required("Required"),
});

interface Props {
    userId: string;
    userName: string;
    active: boolean;
    role: number;
    isDialogOpen: boolean;
    handleCloseDialog: () => void;
}

const roleItems = [
    {label: 'User', value: 0},
    {label: 'Manager', value: 1},
    {label: 'Admin', value: 2}
];

const activeItems = [
    {label: 'Yes', value: true},
    {label: 'No', value: false}
];

const ManageUserDialog = ({userId, userName, active, role, isDialogOpen, handleCloseDialog}: Props) => {
    const theme = useTheme();
    const fullScreen = useMediaQuery(theme.breakpoints.down('md'));
    const state = useGlobalState();

    const initialValues: ManageUserFormInterface = {
        role: role,
        active: active,
    }

    const handleOkDialog = async (values: ManageUserFormInterface) => {
        state.setLoading(true);

        const { role, active } = values;
        try {
            await UsersApi.manageUser({userId, role, active});
        } catch (error) {
            console.log(error);
        } finally {
            state.setLoading(false);
            handleCloseDialog();
        }
    }
    
    return (
        <Dialog
            fullScreen={fullScreen}
            open={isDialogOpen}
            onClose={handleCloseDialog}
            aria-labelledby="responsive-dialog-title"
            sx={{
                "& .MuiDialog-container": {
                    "& .MuiPaper-root": {
                        minWidth: "300px",
                    },
                },
            }}
        >
            <DialogTitle id="responsive-dialog-title">
                {`Manage ${userName}`}
            </DialogTitle>
            <DialogContent>
            <Formik
                    onSubmit={handleOkDialog}
                    initialValues={initialValues}
                    validationSchema={ManageUserSchema}
                >
                    {({ values, errors, touched, handleBlur, handleChange, handleSubmit}) => (
                        <form onSubmit={handleSubmit} id="ManageUserForm">
                            <Grid container spacing={2} sx={{ mt: 3 }}>
                                <Grid item xs={12}>
                                    <TextField
                                        fullWidth
                                        variant="filled"
                                        select
                                        label="Role"
                                        onBlur={handleBlur}
                                        onChange={handleChange}
                                        value={values.role}
                                        id="role"
                                        name="role"
                                        error={!!touched.role && !!errors.role}
                                        helperText={touched.role && errors.role}
                                        defaultValue={role}
                                    >
                                        <MenuItem>
                                            {roleItems.map((role, index) => (
                                                <MenuItem key={index} value={role.value}>
                                                    {role.label}
                                                </MenuItem>
                                            ))}
                                        </MenuItem>
                                    </TextField>
                                </Grid>
                                <Grid item xs={12}>
                                    <TextField
                                        fullWidth
                                        variant="filled"
                                        select
                                        label="Active"
                                        onBlur={handleBlur}
                                        onChange={handleChange}
                                        value={values.active}
                                        id="active"
                                        name="active"
                                        error={!!touched.active && !!errors.active}
                                        helperText={touched.active && errors.active}
                                        defaultValue={active}
                                    >
                                        <MenuItem>
                                            {activeItems.map((active, index) => (
                                                <MenuItem key={index} value={active.value as any}>
                                                    {active.label}
                                                </MenuItem>
                                            ))}
                                        </MenuItem>
                                    </TextField>
                                </Grid>
                            </Grid>
                        </form>
                    )}
                </Formik>
            </DialogContent>
            <DialogActions>
            <Button onClick={handleCloseDialog}>
                Cancel
            </Button>
            <Button type='submit' form="ManageUserForm">
                Confirm
            </Button>
            </DialogActions>
        </Dialog>
    )
}

export default ManageUserDialog;

I tried changing TextField for Select but it happens the same.

英文:

I'm trying to set the 'role' and 'active' values ​​on a form.

The first problem is that the original values ​​of the selectors are not set, which are fetched in the ManageUserDialog Props, so when starting the component the selectors are shown empty.

The second problem is that selecting one of the selector options doesn't set its value.

I attach images of the component, the code and the error delivered by the console.

使用Material UI、Formik和Typescript设置表单值时出现的问题

使用Material UI、Formik和Typescript设置表单值时出现的问题

import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
useMediaQuery,
useTheme,
Grid,
TextField,
MenuItem
} from &#39;@mui/material&#39;;
import { Formik } from &quot;formik&quot;;
import * as yup from &#39;yup&#39;;
import * as UsersApi from &#39;../network/UsersApi&#39;;
import { useGlobalState } from &#39;../context/hookStateProvider&#39;;
interface ManageUserFormInterface {
role: number;
active : boolean;
}
const ManageUserSchema = yup.object().shape({
role: yup.number().required(&quot;Required&quot;),
active: yup.boolean().required(&quot;Required&quot;),
});
interface Props {
userId: string;
userName: string;
active: boolean;
role: number;
isDialogOpen: boolean;
handleCloseDialog: () =&gt; void;
}
const roleItems = [
{label: &#39;User&#39;, value: 0},
{label: &#39;Manager&#39;, value: 1},
{label: &#39;Admin&#39;, value: 2}
];
const activeItems = [
{label: &#39;Yes&#39;, value: true},
{label: &#39;No&#39;, value: false}
];
const ManageUserDialog = ({userId, userName, active, role, isDialogOpen, handleCloseDialog}: Props) =&gt; {
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down(&#39;md&#39;));
const state = useGlobalState();
const initialValues: ManageUserFormInterface = {
role: role,
active: active,
}
const handleOkDialog = async (values: ManageUserFormInterface) =&gt; {
state.setLoading(true);
const { role, active } = values;
try {
await UsersApi.manageUser({userId, role, active});
} catch (error) {
console.log(error);
} finally {
state.setLoading(false);
handleCloseDialog();
}
}
return (
&lt;Dialog
fullScreen={fullScreen}
open={isDialogOpen}
onClose={handleCloseDialog}
aria-labelledby=&quot;responsive-dialog-title&quot;
sx={{
&quot;&amp; .MuiDialog-container&quot;: {
&quot;&amp; .MuiPaper-root&quot;: {
minWidth: &quot;300px&quot;,
},
},
}}
&gt;
&lt;DialogTitle id=&quot;responsive-dialog-title&quot;&gt;
{`Manage ${userName}`}
&lt;/DialogTitle&gt;
&lt;DialogContent&gt;
&lt;Formik
onSubmit={handleOkDialog}
initialValues={initialValues}
validationSchema={ManageUserSchema}
&gt;
{({ values, errors, touched, handleBlur, handleChange, handleSubmit}) =&gt; (
&lt;form onSubmit={handleSubmit} id=&quot;ManageUserForm&quot;&gt;
&lt;Grid container spacing={2} sx={{ mt: 3 }}&gt;
&lt;Grid item xs={12}&gt;
&lt;TextField
fullWidth
variant=&quot;filled&quot;
select
label=&quot;Role&quot;
onBlur={handleBlur}
onChange={handleChange}
value={values.role}
id=&quot;role&quot;
name=&quot;role&quot;
error={!!touched.role &amp;&amp; !!errors.role}
helperText={touched.role &amp;&amp; errors.role}
defaultValue={role}
&gt;
&lt;MenuItem&gt;
{roleItems.map((role, index) =&gt; (
&lt;MenuItem key={index} value={role.value}&gt;
{role.label}
&lt;/MenuItem&gt;
))}
&lt;/MenuItem&gt;
&lt;/TextField&gt;
&lt;/Grid&gt;
&lt;Grid item xs={12}&gt;
&lt;TextField
fullWidth
variant=&quot;filled&quot;
select
label=&quot;Active&quot;
onBlur={handleBlur}
onChange={handleChange}
value={values.active}
id=&quot;active&quot;
name=&quot;active&quot;
error={!!touched.active &amp;&amp; !!errors.active}
helperText={touched.active &amp;&amp; errors.active}
defaultValue={active}
&gt;
&lt;MenuItem&gt;
{activeItems.map((active, index) =&gt; (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
&lt;MenuItem key={index} value={active.value as any}&gt;
{active.label}
&lt;/MenuItem&gt;
))}
&lt;/MenuItem&gt;
&lt;/TextField&gt;
&lt;/Grid&gt;
&lt;/Grid&gt;
&lt;/form&gt;
)}
&lt;/Formik&gt;
&lt;/DialogContent&gt;
&lt;DialogActions&gt;
&lt;Button onClick={handleCloseDialog}&gt;
Cancel
&lt;/Button&gt;
&lt;Button type=&#39;submit&#39; form=&quot;ManageUserForm&quot;&gt;
Confirm
&lt;/Button&gt;
&lt;/DialogActions&gt;
&lt;/Dialog&gt;
)
}
export default ManageUserDialog;

I tried changing TextField for Select but it happens the same.

答案1

得分: 0

我解决了问题,问题是我在MenuItem内部使用了MenuItem。我只在每个TextField内部保留了地图中的一个。

import {
    Button,
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    useMediaQuery,
    useTheme,
    Grid,
    TextField,
    MenuItem
} from '@mui/material';
import { Formik } from "formik";
import * as yup from 'yup';
import * as UsersApi from '../network/UsersApi';
import { useGlobalState } from '../context/hookStateProvider';

interface ManageUserFormInterface {
    role: number;
    active: boolean;
}

const ManageUserSchema = yup.object().shape({
    role: yup.number().required("Required"),
    active: yup.boolean().required("Required"),
});

interface Props {
    userId: string;
    userName: string;
    active: boolean;
    role: number;
    isDialogOpen: boolean;
    handleCloseDialog: () => void;
}

const roleItems = [
    { label: 'User', value: 0 },
    { label: 'Manager', value: 1 },
    { label: 'Admin', value: 2 }
];

const activeItems = [
    { label: 'Yes', value: true },
    { label: 'No', value: false }
];

const ManageUserDialog = ({ userId, userName, active, role, isDialogOpen, handleCloseDialog }: Props) => {
    const theme = useTheme();
    const fullScreen = useMediaQuery(theme.breakpoints.down('md'));
    const state = useGlobalState();

    const initialValues: ManageUserFormInterface = {
        role: role,
        active: active,
    }

    const handleOkDialog = async (values: ManageUserFormInterface) => {
        state.setLoading(true);

        const { role, active } = values;
        try {
            await UsersApi.manageUser({ userId, role, active });
        } catch (error) {
            console.log(error);
        } finally {
            state.setLoading(false);
            handleCloseDialog();
        }
    }

    return (
        <Dialog
            fullScreen={fullScreen}
            open={isDialogOpen}
            onClose={handleCloseDialog}
            aria-labelledby="responsive-dialog-title"
            sx={{
                "& .MuiDialog-container": {
                    "& .MuiPaper-root": {
                        minWidth: "300px",
                    },
                },
            }}
        >
            <DialogTitle id="responsive-dialog-title">
                {`Manage ${userName}`}
            </DialogTitle>
            <DialogContent>
                <Formik
                    onSubmit={handleOkDialog}
                    initialValues={initialValues}
                    validationSchema={ManageUserSchema}
                >
                    {({ values, errors, touched, handleBlur, handleChange, handleSubmit }) => (
                        <form onSubmit={handleSubmit} id="ManageUserForm">
                            <Grid container spacing={2} sx={{ mt: 3 }}>
                                <Grid item xs={12}>
                                    <TextField
                                        fullWidth
                                        variant="filled"
                                        select
                                        label="Role"
                                        onBlur={handleBlur}
                                        onChange={handleChange}
                                        value={values.role}
                                        id="role"
                                        name="role"
                                        error={!!touched.role && !!errors.role}
                                        helperText={touched.role && errors.role}
                                    >
                                        {/* 这里有变化 */}
                                        {roleItems.map((r, index) => (
                                            <MenuItem key={index} value={r.value}>
                                                {r.label}
                                            </MenuItem>
                                        ))}
                                    </TextField>
                                </Grid>
                                <Grid item xs={12}>
                                    <TextField
                                        fullWidth
                                        variant="filled"
                                        select
                                        label="Active"
                                        onBlur={handleBlur}
                                        onChange={handleChange}
                                        value={values.active}
                                        id="active"
                                        name="active"
                                        error={!!touched.active && !!errors.active}
                                        helperText={touched.active && errors.active}
                                    >
                                        {/* 这里有变化 */}
                                        {activeItems.map((active, index) => (
                                            <MenuItem key={index} value={active.value as any}>
                                                {active.label}
                                            </MenuItem>
                                        ))}
                                    </TextField>
                                </Grid>
                            </Grid>
                        </form>
                    )}
                </Formik>
            </DialogContent>
            <DialogActions>
                <Button onClick={handleCloseDialog}>
                    Cancel
                </Button>
                <Button type='submit' form="ManageUserForm">
                    Confirm
                </Button>
            </DialogActions>
        </Dialog>
    )
}

export default ManageUserDialog;
英文:

I solved it, the problem was that I used MenuItem inside MenuItem. I only left the one inside the map in each TextField.

import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
useMediaQuery,
useTheme,
Grid,
TextField,
MenuItem
} from &#39;@mui/material&#39;;
import { Formik } from &quot;formik&quot;;
import * as yup from &#39;yup&#39;;
import * as UsersApi from &#39;../network/UsersApi&#39;;
import { useGlobalState } from &#39;../context/hookStateProvider&#39;;
interface ManageUserFormInterface {
role: number;
active : boolean;
}
const ManageUserSchema = yup.object().shape({
role: yup.number().required(&quot;Required&quot;),
active: yup.boolean().required(&quot;Required&quot;),
});
interface Props {
userId: string;
userName: string;
active: boolean;
role: number;
isDialogOpen: boolean;
handleCloseDialog: () =&gt; void;
}
const roleItems = [
{label: &#39;User&#39;, value: 0},
{label: &#39;Manager&#39;, value: 1},
{label: &#39;Admin&#39;, value: 2}
];
const activeItems = [
{label: &#39;Yes&#39;, value: true},
{label: &#39;No&#39;, value: false}
];
const ManageUserDialog = ({userId, userName, active, role, isDialogOpen, handleCloseDialog}: Props) =&gt; {
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down(&#39;md&#39;));
const state = useGlobalState();
const initialValues: ManageUserFormInterface = {
role: role,
active: active,
}
const handleOkDialog = async (values: ManageUserFormInterface) =&gt; {
state.setLoading(true);
const { role, active } = values;
try {
await UsersApi.manageUser({userId, role, active});
} catch (error) {
console.log(error);
} finally {
state.setLoading(false);
handleCloseDialog();
}
}
return (
&lt;Dialog
fullScreen={fullScreen}
open={isDialogOpen}
onClose={handleCloseDialog}
aria-labelledby=&quot;responsive-dialog-title&quot;
sx={{
&quot;&amp; .MuiDialog-container&quot;: {
&quot;&amp; .MuiPaper-root&quot;: {
minWidth: &quot;300px&quot;,
},
},
}}
&gt;
&lt;DialogTitle id=&quot;responsive-dialog-title&quot;&gt;
{`Manage ${userName}`}
&lt;/DialogTitle&gt;
&lt;DialogContent&gt;
&lt;Formik
onSubmit={handleOkDialog}
initialValues={initialValues}
validationSchema={ManageUserSchema}
&gt;
{({ values, errors, touched, handleBlur, handleChange, handleSubmit}) =&gt; (
&lt;form onSubmit={handleSubmit} id=&quot;ManageUserForm&quot;&gt;
&lt;Grid container spacing={2} sx={{ mt: 3 }}&gt;
&lt;Grid item xs={12}&gt;
&lt;TextField
fullWidth
variant=&quot;filled&quot;
select
label=&quot;Role&quot;
onBlur={handleBlur}
onChange={handleChange}
value={values.role}
id=&quot;role&quot;
name=&quot;role&quot;
error={!!touched.role &amp;&amp; !!errors.role}
helperText={touched.role &amp;&amp; errors.role}
&gt;
{/* Here Changes */}
{roleItems.map((r, index) =&gt; (
&lt;MenuItem key={index} value={r.value}&gt;
{r.label}
&lt;/MenuItem&gt;
))}
&lt;/TextField&gt;
&lt;/Grid&gt;
&lt;Grid item xs={12}&gt;
&lt;TextField
fullWidth
variant=&quot;filled&quot;
select
label=&quot;Active&quot;
onBlur={handleBlur}
onChange={handleChange}
value={values.active}
id=&quot;active&quot;
name=&quot;active&quot;
error={!!touched.active &amp;&amp; !!errors.active}
helperText={touched.active &amp;&amp; errors.active}
&gt;
{/* Here Changes */}
{activeItems.map((active, index) =&gt; (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
&lt;MenuItem key={index} value={active.value as any}&gt;
{active.label}
&lt;/MenuItem&gt;
))}
&lt;/TextField&gt;
&lt;/Grid&gt;
&lt;/Grid&gt;
&lt;/form&gt;
)}
&lt;/Formik&gt;
&lt;/DialogContent&gt;
&lt;DialogActions&gt;
&lt;Button onClick={handleCloseDialog}&gt;
Cancel
&lt;/Button&gt;
&lt;Button type=&#39;submit&#39; form=&quot;ManageUserForm&quot;&gt;
Confirm
&lt;/Button&gt;
&lt;/DialogActions&gt;
&lt;/Dialog&gt;
)
}
export default ManageUserDialog;

huangapple
  • 本文由 发表于 2023年6月6日 10:06:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/76411004.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定