NextJS 和 Formik:select 下拉列表中的条件/动态呈现表单字段

NextJS and Formik: Conditional / Dynamic rendering form fields on select dropdown

我在网页上使用 Next.jsFormik 进行条件渲染时遇到问题。

所以我的页面上有一个名为 commands 的数组,这很简单:

const commands = [
    {
        value: 'launch',
        display_name: 'LAUNCH ROCKET!',
    },
    {
        value: 'delay_launch',
        display_name: 'LAUNCH IN..',
    },
    {
      ....list of elements, they are not API fetched!
    }
];

我的页面上需要一个网络表单(组件)(基于 Formik

组件如下所示:

<Container>
    <Formik
        initialValues={{ command: 'launch', arguments: 'test'}}
        onSubmit={async (values, { setSubmitting }) => {
            await setSubmitting(false);
            await Router.push(`/${values.command}`);
        }}
    >
    {({
            values,
            errors,
            touched,
            handleChange,
            handleBlur,
            handleSubmit,
            /* and other goodies */
        }) => (
        <form onSubmit={handleSubmit} noValidate autoComplete="off">
            <Grid container spacing={3} direction="row" justify="center" alignItems="center">
                <Grid item xs={3}>
                    <TextField
                        name="command"
                        select
                        label="Select command"
                        className={classes.dropdown}
                        onChange={handleChange}
                        onBlur={handleBlur}
                        value={values.command}
                        variant="outlined"
                    >
                        {commands.map((option) => (
                            <MenuItem key={option.value} value={option.value}>
                                {option.label}
                            </MenuItem>
                        ))}
                    </TextField>
                </Grid>
                {/* IF COMMAND IN SELECT DROPDPWN === LAUNCH THEN RENDER THIS*/}
                {values.command === "launch" && (
                    <React.Fragment>
                        <Grid item xs={3}>
                            <TextField
                                text-field
                            />
                        </Grid>
                        <Grid item xs={1}>
                            <Typography variant="h3" align="center" style={{textTransform: 'uppercase', margin: '0'}}>
                                @
                            </Typography>
                        </Grid>
                        <Grid item xs={3}>
                            <TextField
                                another text-field
                            </TextField>
                        </Grid>
                    </React.Fragment>
                )}
            </Grid>
        </form>
    )}
    </Formik>
</Container>

它(应该)如何工作?

当您在页面上 select 下拉菜单(以 Formik 的形式)时,它会呈现其他字段,具体取决于 select 值 .

问题:

正如你所看到的,如果我继续这样写代码,它会是一样的,就好像我把每个 if 语句一个一个地写出来。

所以如果我的命令列表有 10 多个不同的命令,它将有 10+ if 个块。但是我不需要使用 commands.map => 在我的表单中一次渲染它们。我只想查看我的表单中需要的那些字段,只有在 selected in dropdown.

中输入正确的命令时

像这样(伪代码风格):

IF IN MY FORM SELECTED COMMAND:
  LAUNCH => THEN ADD 2 ADDITIONAL FIELDS IN THIS FORM
  DELAYED LAUNCH => THEN ADD 3 ADDITIONAL FIELDS IN THIS FORM
  ...

那么如何实现呢?

我想我应该在我的 commands 数组中添加第 3 个字段,例如:

const commands = [
    {
        value: 'launch',
        display_name: 'LAUNCH ROCKET!',
        render_code: `<React.Fragment>
                        <Grid item xs={3}>
                            <TextField
                                text-field
                            />
                        </Grid>
                        <Grid item xs={1}>
                            <Typography variant="h3" align="center" style={{textTransform: 'uppercase', margin: '0'}}>
                                @
                            </Typography>
                        </Grid>
                        <Grid item xs={3}>
                            <TextField
                                another text-field
                            </TextField>
                        </Grid>
                    </React.Fragment>`
    },
    ....
]

但是如何根据确定的 selected 值在我的表单中呈现它?我猜应该是这样的:Map.get(number),但我还没有找到任何例子,而且我不知道渲染代码片段应该如何存储在数组中。如果我将它存储在一个 string 值中,可以吗?

已更新:

我正在尝试使用 render_code 示例,就像上面的示例一样,通过:

{commands.find(x => {if (x.value === values.command) return x.rendring_code})}

但问题是,如果将 JSX 片段存储为 string,它会变成:

code: "<React.Fragment>\n                <Grid item xs={3}>\n 

所有这些 \n 用于跳行和其他格式符号,但我不能存储纯 JSX 因为在那种情况下我有一个渲染错误,导致 <TextField>onChange={handleChange} 之类的属性 declared/defined 仅在 Formik 表单内,但不在页面外。

我在 Formik 的 Github Issue #751 and at this article 上发现了一个相关问题。所以我发现了一些不同但相关的问题解决方案。

这里是snippet @CodeSandbox and

所以解决方案是基于原始表单的子组件,它是基于 select 字段呈现的。 (正是我需要的)。

不幸的是,我没有解决重复代码问题,而是很好地构建代码并只呈现表单的必要部分。