首页 > 解决方案 > NextJS 和 Formik:选择下拉菜单上的条件/动态呈现表单字段

问题描述

我的网页上Next.js的条件渲染有问题。Formik

所以我在我的页面上命名了一个数组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>

它(应该)如何工作?

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

问题:

如您所见,如果我继续这样编写代码,它会是一样的,就好像我if一个接一个地编写每个语句一样。

因此,如果我的命令列表有 10 多个不同的命令,它将有 10 多个if块。但我不需要以我的形式一次性渲染它们,使用commands.map =>. 我只想查看表单中需要的那些字段,只有当在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,例如:

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>`
    },
    ....
]

但是如何根据确定的选定值以我的形式呈现它?我想应该有类似的东西: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}Formik

标签: javascriptreactjsformsnext.jsformik

解决方案


我在 Formik 的 Github第 751 期本文中发现了一个相关问题。所以我发现我的问题有点不同,但相关的解决方案。

这是一个片段@CodeSandboxStackOverflow 的答案

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

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


推荐阅读