使用 Redux、Thunk、Axios 创建多部分表单组件

Posted

技术标签:

【中文标题】使用 Redux、Thunk、Axios 创建多部分表单组件【英文标题】:Creating a multipart form component with Redux, Thunk, Axios 【发布时间】:2021-06-22 19:34:51 【问题描述】:

我正在尝试创建我在 React 中创建的多类型表单的最后阶段。我想我即将创建一个 handleSubmit 方法来将我的多部分表单数据发布到我的后端数据库,但是我收到了以下与 CORS 问题有关的错误消息。

我是否要以正确的方式添加到我的 Redux 存储和后端?我是否需要在我的服务“createDiveSpot”方法中添加某种解析器来分隔文本、数字和图像?这些错误消息是否来自我没有请求标头?

渲染页面时的错误消息

Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

控制台错误

    // state for the current field value
    const [spot, setSpot] = useState(
        diveLocation: "",
        diveRegionID: "",
        diveTypeID: "",
        diveSpotDescription: "",
        diveSpotPhotos: "",
        error: ''
    );

    // all onChange functions do the exact same thing, so you only need one
    // pass to a component like onChange=handleChange('typeID')
    const handleChange = (property) => (e) => 
        setSpot(
            // override the changed property and keep the rest
            ...spot,
            [property]: e.target.value,
        );
    

    // get access to dispatch
    const dispatch = useDispatch();

    // useEffect with an empty dependency array is the same as componentDidMount
    useEffect(() => 
        dispatch(requireFieldData());
    , []);

    const handleSubmitDiveSpot = () => 

        const diveSpot = 
            diveLocation: spot.diveLocation || undefined,
            diveRegionID: spot.diveRegionID || undefined,
            diveSpotTypeID: spot.diveSpotTypeID || undefined,
            diveSpotDescription: spot.diveSpotDescription || undefined,
            diveSpotPhotos: spot.diveSpotPhotos || undefined
        

        // do some stuff with the form
        createDiveSpot(diveSpot).then((data) => 
            if (data.error) 
                setSpot( ...spot, error: data.error)
             else 
                setSpot( ...spot, error: '', open: true)
            
        )
        // do we need to save this to the backend? or just to redux?
        dispatch(addDiveSpot(spot));
        

    const classes = useStyles;

    return (

        // <AppBar title="Enter your dive details"></AppBar>
        <form className="diveSpotForm" method="POST" encType="multipart/form-data" onSubmit=handleSubmitDiveSpot>

            <>
                <Grid container spacing=3
                      direction="row"
                      justify="center"
                      alignItems="center">
                    <Grid item xs=4>
                    <FormControl className=classes.formControl>
                        <PopulateDropdown
                            dataList=diveTypeList
                            titleProperty="diveType" // option label property
                            valueProperty="diveTypeID" // option value property
                            name="diveType"
                            placeholder="Dive Type"
                            label="Select Dive Type"
                            value=spot.diveTypeID
                            onChange=handleChange("diveTypeID")/>
                    </FormControl>
                    </Grid>
                    <br />
                    <Grid item xs=4>
                        <FormControl className=classes.formControl>
                            <PopulateDropdown
                                dataList=regionList
                                titleProperty="diveRegion" // option label property
                                valueProperty="diveRegionID" // option value property
                                name="diveRegion"
                                placeholder="Dive Region"
                                label="Select Region"
                                value=spot.diveRegionID
                                onChange=handleChange("regionID")/>
                        </FormControl>
                    </Grid>
                    <br />
                    <Grid item xs=4>
                        <TextField
                            label="diveLocation"
                            placeholder="Dive Location"
                            name="diveLocation"
                            margin="normal"
                            value=spot.diveLocation
                            onChange=handleSubmitDiveSpot("diveLocation")/>
                    </Grid>
                    <br />
                    <Grid item xs=10>
                        <FormControl fullWidth className=classes.margin>
                            <TextField
                                label="Description"
                                name="diveSpotDescription"
                                value=spot.diveSpotDescription
                                onChange=handleSubmitDiveSpot("diveSpotDescription")
                                multiline
                                rowsMax=6/>
                        </FormControl>
                    </Grid>
                    <br />
                    <Grid item xs=12>
                        <FormControl fullWidth className=classes.margin>
                            <label for="photos">Photo Upload</label>
                            <input
                                type="file"
                                name="photo"
                                value=spot.diveSpotPhotos
                                onChange=handleSubmitDiveSpot("diveSpotPhotos")/>
                        </FormControl>
                    </Grid>
                    <br />
                    <Grid item xs=3>
                        <Button variant="primary" type="submit">
                            Submit</Button>
                        <br />
                    </Grid>
                </Grid>
            </>
        </form>

【问题讨论】:

邮件是404 Not Found -- 你确定/api/divespots/createdivespot 是正确的URL吗?你的后端可以处理它吗?通常它只是像/api/divespots 这样的一条路径,您将使用PUTPOST 请求类型来表示您正在创建一个项目,而GET 则用于读取数据。 HTTP Request Methods 部分输入有错误的onChange 函数。你有handleSubmitDiveSpot("diveLocation"),但它应该是handleChange("diveLocation")。这就是“太多重新渲染”的原因。 【参考方案1】:

我认为问题始于您如何向onChange 提供处理程序。如果您在渲染时调用函数,而不是传递函数的引用,则会出现超出嵌套更新的问题。

也许,尝试将 onChange=handleChange("diveTypeID") 更改为 onChange=(e)=&gt; handleChange(e,"diveTypeID")onChange=handleChange.bid(this,"diveTypeID")

【讨论】:

handleChange 是一个柯里化函数const handleChange = (property) =&gt; (e) =&gt; ,所以可以使用onChange=handleChange("diveTypeID"),因为它会创建一个事件处理程序(我在另一个问题上为他编写了该函数,哈哈)。 handleSubmitDiveSpot 不是 curried 函数,所以你所说的关于handleSubmitDiveSpot 是正确的。【参考方案2】:

您收到该错误是因为您需要更改设置 onChange 道具的方式。

代替:

onChange=handleChange("diveTypeID")

你应该有这个:

onChange=(event, id) => handleChange(event, "diveTypeID"
React onChange Events React - Forms

【讨论】:

以上是关于使用 Redux、Thunk、Axios 创建多部分表单组件的主要内容,如果未能解决你的问题,请参考以下文章

React + redux + axios + thunk,等待interceptors.response 刷新token

使用 axios 和 redux-thunk 以 redux-form 发布请求

使用 axios 的 redux-thunk 的通用数据加载器

使用 Redux-Thunk / Axios 从 onUploadProgress 事件调度操作

Redux Thunk操作,axios返回多个值

带有 axios 返回多个值的 Redux Thunk 操作