首页 > 解决方案 > React,如何在 axios PUT 请求后更新组件

问题描述

我正在尝试为我的问题找到解决方案。情况是这样的:我有一个 EducationComponent,其中包含 GET 请求(使用 axios),然后返回所有教育数组的 .map,但是 .map 创建的每个项目的渲染都在另一个组件中,即 EducationItemComponent,它包含一个带有表单的折叠,您可以使用 PUT 请求(使用 axios 制作)在数据库中编辑该项目。

一切都运行良好,即使我确信我制造了很多混乱并且肯定会是一些更简单的方法来实现我的应用程序,但我对 React 和 JSX 非常陌生,这是我现在能做的最大的事情。

我要做的是:一旦我填写了表格并提交了它,并且 PUT 请求更改了我数据库中的数据,我想重新渲染该项目并立即查看我的更改已经完成了,但我找不到任何方法来做到这一点。

以下是 EducationComponent 中的代码:

import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import axios from 'axios';

import { addEducation } from '../../redux/actions/educationActions';
import { EducationItem } from './EducationItemComponent';

export const Education = () => {

    const education = useSelector((state) => state.education.education);

    const { id, school, date, description } = education ?? {};

    const dispatch = useDispatch();

    const fetchEducation = async (id, school, date, descr) => {
        const response = await axios
            .get('http://localhost:3005/education')
            .catch((err) => {
                console.log('Err', err);
            });
        dispatch(addEducation(response.data));
        console.log(response.data[0].school);
    }

    useEffect(() => {
        fetchEducation();
    }, []);

    return (
        <div className="education clearfix">
            <h2 className="small-heading">EDUCATION</h2>
            <div className="education-container col-lg-10 col-lg-offset-1 col-md-12 col-md-offset-0 col-sm-10 col-sm-offset-1">

                { /* Education items */}
                {education.map(educ =>
                    <>
                        <EducationItem key={educ.id} id={educ.id} school={educ.school} descr={educ.description} date={educ.date} />
                    </>
                )}
            </div>
        </div>
    );
}

这是 EducationItemComponent 的代码,它从 .map 中渲染每个组件:

import React from 'react';
import { Collapse } from 'reactstrap';
import { ButtonGroup, Button, Form } from 'react-bootstrap';
import { faEdit, faTrashAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import axios from 'axios';

const putEducation = async (id, school, date, descr) => {

    var educUrl = 'http://localhost:3005/education/' + id;
    const newEducation = {
        id: id,
        school: school,
        date: date,
        description: descr
    }

    const response = await axios
        .put(educUrl, newEducation)
        .catch((err) => {
            console.log('Err', err);
        });
}

const submitEducationEdit = (event, id, success) => {
    event.preventDefault();
    putEducation(id, event.target.school.value, event.target.date.value, event.target.description.value);
}

export class EducationItem extends React.Component {
    constructor(props) {
        super(props);

        this.toggle = this.toggle.bind(this);
        this.state = { 
            open: false
        };
    }

    toggle() {
        this.setState({ open: !this.state.open });
    }

    render() {
        return (
            <>
                <div className="item" key={this.props.id}>
                    <div className="bullet hidden-xs">
                    </div>
                    <div className="education-content">
                        <h3>{this.props.school}<span> / {this.props.date}</span></h3>
                        <p>
                            {this.props.descr}
                        </p>
                    </div>
                    <div className="edit">
                        <ButtonGroup vertical>
                            <Button onClick={this.toggle} variant="success"><FontAwesomeIcon icon={faEdit} /></Button>
                            <Button variant="danger"><FontAwesomeIcon icon={faTrashAlt} /></Button>
                        </ButtonGroup>
                    </div>

                </div>

                <Collapse isOpen={this.state.open}>
                    <Form onSubmit={(e) => submitEducationEdit(e, this.props.id, this.state.success)} id="educationEditFormId">
                        <Form.Row>
                            <Form.Group className={"half"}>
                                <Form.Label>School</Form.Label>
                                <Form.Control
                                    name="school"
                                    as="textarea"
                                    rows={1} />
                            </Form.Group>
                            <Form.Group className={"half"}>
                                <Form.Label>Date</Form.Label>
                                <Form.Control
                                    name="date"
                                    as="textarea"
                                    rows={1} />
                            </Form.Group>
                        </Form.Row>
                        <Form.Group>
                            <Form.Label>Description</Form.Label>
                            <Form.Control
                                name="description"
                                as="textarea"
                                rows={5} />
                        </Form.Group>
                        <Button
                            variant="success"
                            type="submit"
                            size="sm" >
                            Submit
                        </Button>
                    </Form>
                </Collapse>
            </>
        );
    }
}

我还尝试在educationReducer 中编写putEducation 和fetchEducation 常量(我使用Redux 来管理我的商店),但是我不能使用例如useDispatch() 挂钩,因为我不能在顶层使用它,而且我找不到使用它的方法,我不知道是否有另一种方法来调度我从 axios GET 请求中获得的响应。如果我可以在educationReducer 中编写它们,那可能会更容易,因为我可以从我的两个组件中调用它们,然后使用 useEffect 挂钩来刷新项目,或者类似的东西。我真的不知道如何解决这个问题,什么是最好的方法。

提前谢谢你们。

这是我现在的educationActions的样子:

import * as ActionTypes from '../constants/ActionTypes';

export const addEducation = (education) => {
    return {
        type: ActionTypes.ADD_EDUCATION,
        payload: education
    };
};

这是educationReducer:

import * as ActionTypes from '../constants/ActionTypes';

const initialState = {
    education: [],
}

export const educationReducer = (state = initialState, { type, payload }) => {
    switch (type) {
        case ActionTypes.ADD_EDUCATION:
            return { ...state, education: payload };
        default:
            return state;
    }
}

标签: reactjsreact-reduxaxios

解决方案


推荐阅读