【问题标题】:How to add child array input field dynamically in React JS如何在 React JS 中动态添加子数组输入字段
【发布时间】:2021-09-11 12:31:39
【问题描述】:

这是我的代码

const useStyles = makeStyles((theme) => ({
root: {
    '& .MuiTextField-root': {
        margin: theme.spacing(1)
    },
},
button: {
    margin: theme.spacing(1)
}
}))

function CreateCourse() {

const classes = useStyles();
const [sectionFields, setSectionFields] = useState([{
    sectionName: '',
    overview: '',
    videoContents: [{
        videoName: '', videoUrl: ''
    }]
}])

function handleChangInput(index, event) {
    const values = [...sectionFields];
    values[index][event.target.name] = event.target.value;
    setSectionFields(values);
}

function handleChangVideoInput(index, i, event) {
    const values = [...sectionFields];
    values[index].videoContents[i][event.target.name] = event.target.value;
    setSectionFields(values);
    console.log(index, event.target.name)
}


const handleSubmit = (event) => {
    event.preventDefault();
    console.log("Input Field ", sectionFields)
}

const handleRemoveFields = (index) => {
    const values = [...sectionFields];
    values.splice(index, 1)
    setSectionFields(values)
}

const handleAddFields = () => {
    setSectionFields([...sectionFields, {
        sectionName: '',
        overview: '',
        videoContents: [{videoName: '', videoUrl: ''}]
    }])
}

return (
    <div className='container mb-5'>
        <Container>
            <h1>Add New Member</h1>
            <form className={classes.root} onSubmit={handleSubmit}>
                {sectionFields.map((inputField, index) => (
                    <div key={index}>
                        <TextField
                            name="sectionName"
                            label="Section Name"
                            variant="filled"
                            value={inputField?.sectionName}
                            onChange={event => handleChangInput(index, event)}
                        />
                        <TextField
                            name="overview"
                            label="Section Overview"
                            variant="filled"
                            value={inputField?.overview}
                            onChange={event => handleChangInput(index, event)}
                        />

                        <IconButton onClick={() => handleRemoveFields(index)}>
                            <RemoveIcon/>
                        </IconButton>
                        <IconButton onClick={handleAddFields}>
                            <AddIcon/>
                        </IconButton>

                        {inputField?.videoContents?.map((v, i) => (
                            <div key={i}>
                                <TextField
                                    name="videoName"
                                    label="Enter Video Name"
                                    variant="filled"
                                    value={v.videoName}
                                    onChange={event => handleChangVideoInput(index, i, event)}
                                />
                                <TextField
                                    name="videoUrl"
                                    label="Enter Video Url"
                                    variant="filled"
                                    value={v.videoUrl}
                                    onChange={event => handleChangVideoInput(index, i, event)}
                                />
                                
                            </div>
                        ))}
                    </div>
                ))}
                <Button
                    className={classes.button}
                    variant='contained'
                    color='primary'
                    type='submit'
                    endIcon={<Icon/>}
                    onClick={handleSubmit}
                >
                    SEND
                </Button>
            </form>
        </Container>
    </div>

);
}
export default CreateCourse;

屏幕截图中的输出

当我点击加号图标时,会创建一个新的输入,例如

但是我想要一个 sectionName 有很多 videoName 和 videoUrl 就像我想在 videoUrl 一侧创建加号图标,当用户单击加号图标时,它会创建用户想要的多个 videoName 和 videoUrl,如果用户单击部分然后它创建一节行和一个视频行。如何使用 react 解决这个问题?

【问题讨论】:

    标签: javascript arrays reactjs react-hooks


    【解决方案1】:

    首先,当您使用状态的当前值来计算新的状态值时,最好使用回调函数。这样它就不会受到重新渲染的影响,并保证计算使用最新的状态值。

    假设你有

    const [state, setState] = useState([]);
    

    不要使用:

    const next = [...state, newElement];
    setState(next);
    

    但是,请使用:

    setState((previous) => [...previous, newElement]);
    

    为了在嵌套数组中添加更多字段,您可以像这样更新状态:

    function addToSection(i) {
      setSectionFields((prev) => (
        const updatedSection = {
          ...prev[i],
          videoContents: [
            ...prev[i].videoContents,
            { videoName: '', videoUrl: '' },
          ],
        };
        return prev.map((section, index) => {
          return index === i ? updatedSection : section;
        });
      );
    }
    

    【讨论】:

    • 我的代码没有问题,我只是想添加一些我做不到的额外功能
    • 更新了我的答案
    【解决方案2】:

    经过几个小时的尝试,我终于做到了,感谢@GalAbra,他节省了我很多时间,我发布这个是因为如果它对任何人都有帮助

    import React, {useState} from "react";
    import Container from "@material-ui/core/Container";
    import {TextField} from "@material-ui/core";
    import Icon from "@material-ui/icons/Send";
    import {makeStyles} from "@material-ui/core/styles";
    import Button from "@material-ui/core/Button";
    import IconButton from "@material-ui/core/IconButton";
    import RemoveIcon from '@material-ui/icons/Delete';
    import AddIcon from "@material-ui/icons/Add";
    
     const useStyles = makeStyles((theme) => ({
      root: {
        '& .MuiTextField-root': {
            margin: theme.spacing(1)
        },
     },
     button: {
        margin: theme.spacing(1)
     }}))
    
    function CreateCourse() {
    
    const classes = useStyles();
    
    const [sectionFields, setSectionFields] = useState([{
        sectionName: '',
        overview: '',
        videoContents: [{
            videoName: '', videoUrl: ''
        }]}])
    
    
    function handleChangInput(index, event) {
        const values = [...sectionFields];
        values[index][event.target.name] = event.target.value;
        setSectionFields(values);
    }
    
    function handleChangVideoInput(index, i, event) {
        const values = [...sectionFields];
        values[index].videoContents[i][event.target.name] = event.target.value;
        setSectionFields(values);
        console.log(index, event.target.name)
    }
    
    
    const handleSubmit = (event) => {
        event.preventDefault();
        console.log("Input Field ", sectionFields)
    }
    
    const handleRemoveFields = (index) => {
        const values = [...sectionFields];
        if(index > 0) values.splice(index, 1)
        setSectionFields(values)
    }
    
    const handleRemoveVideoFields = (index, i) => {
        const values = [...sectionFields];
        if(i > 0)
        values[index].videoContents.splice(i, 1)
        setSectionFields(values)
    }
    
    
    const handleAddFields = (index) => {
        setSectionFields((prevState => (
            [...prevState, {
                videoContents: [{videoName: '', videoUrl: ''}]
            }]
        )))
    }
    
    const handleAddVideoFields = (i) => {
        setSectionFields(prev => {
            const updatedSection = {
                ...prev[i],
                videoContents: [
                    ...prev[i].videoContents,
                    {videoName: '', videoUrl: ''},
                ],
            };
            return prev.map((section, index) => {
                return index === i ? updatedSection : section;
            });
        })
    }
    
    
    return (
        <div className='container mb-5'>
            <Container>
                <form className={classes.root} onSubmit={handleSubmit}>
                    {sectionFields.map((inputField, index) => (
                        <div key={index}>
                            <p className='mb-0 mt-3 ml-2'>Enter Section Name</p>
                            <TextField
                                name="sectionName"
                                label="Section Name"
                                variant="filled"
                                value={inputField?.sectionName}
                                onChange={event => handleChangInput(index, event)}
                            />
                            <TextField
                                name="overview"
                                label="Section Overview"
                                variant="filled"
                                value={inputField?.overview}
                                onChange={event => handleChangInput(index, event)}
                            />
    
                            <IconButton onClick={() => handleRemoveFields(index)}>
                                <RemoveIcon/>
                            </IconButton>
                            <IconButton onClick={() => handleAddFields(index)}>
                                <AddIcon/>
                            </IconButton>
    
                            {inputField?.videoContents?.map((v, i) => (
                                <div key={i}>
                                    <TextField
                                        name="videoName"
                                        label="Enter Video Name"
                                        variant="filled"
                                        value={v.videoName}
                                        onChange={event => handleChangVideoInput(index, i, event)}
                                    />
                                    <TextField
                                        name="videoUrl"
                                        label="Enter Video Url"
                                        variant="filled"
                                        value={v.videoUrl}
                                        onChange={event => 
                               handleChangVideoInput(index, i, event)}
                                    />
    
                                    <IconButton onClick={() => 
                                        handleRemoveVideoFields(index, i)}>
                                        <RemoveIcon/>
                                    </IconButton>
                                    <IconButton onClick={() => 
                                     handleAddVideoFields(index)}>
                                        <AddIcon/>
                                    </IconButton>
                                </div>
                            ))}
                        </div>
                    ))}
                    <Button
                        className={classes.button}
                        variant='contained'
                        color='primary'
                        type='submit'
                        endIcon={<Icon/>}
                        onClick={handleSubmit}
                    >
                        SEND
                    </Button>
                </form>
            </Container>
        </div>
    
    );
    }
    export default CreateCourse;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-09
      • 1970-01-01
      • 2014-01-03
      • 2016-07-30
      • 2019-08-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多