从 React 功能组件中调用 API

Making API calls out of React Functional Component

我是 React 的新手,我知道函数式和 Class 组件的概念以及 useEffect 和 useState 等 Hook;因此,我在将这些知识付诸实践时遇到了麻烦,因为我正在研究以下 React 组件,该组件进行了简单的 Javascript API 调用,我现在想将其转换为“真实的”React API调用,使用State和Hooks。

我的问题如下:我想呈现 API 返回的员工对象,从员工的名字和姓氏开始,然后是其他信息。

对 API 的请求在 Javascript 中正常进行,并且 returns 需要数据;因此,我不太确定根据定义将状态设置为什么(0?假?其他?这取决于什么,我怎么知道?)。

代码如下:

import React, {useEffect, useState} from 'react';
import { Link } from "react-router-dom";
import {
    Container,
    Row,
    Col,
    Card,
    CardBody,
    Table,
    Button, Alert, Modal, ModalHeader, ModalBody
} from "reactstrap";


const ContactsList = (props) => {

        let request = new XMLHttpRequest()

        // Open a new connection, using the GET request on the URL endpoint
        request.open('GET', 'https://somenet.net/employee', true)

        request.onload = function () {
            // Begin accessing JSON data here
            let data = JSON.parse(this.response)

           data.forEach((employee) => {
                // Log each movie's title
                console.log(employee.id, employee.firstname, employee.lastname, employee.performance_index, employee.min_customer_distance, employee.customer_distance_radius, employee.webfleet_obj_id, employee.default_employee_working_schedule_id)
            })
        }
        // Send request
        request.send()

        let employees = [


            {
                id: 1, img: "Null", name: "David McHenry", designation: "UI/UX Designer", email: "david@skote.com", projects: "125",
                skills: [
                    { name: "Photoshop" },
                    { name: "illustrator" }
                ]
            }
        ]

       const users = [
            {
                id: 1, img: "Null", name: "David McHenry", designation: "UI/UX Designer", email: "david@skote.com", projects: "125",
                skills: [
                    { name: "Photoshop" },
                    { name: "illustrator" }
                ]
            },
            {
                id: 2, img: avatar2, name: "Frank Kirk", designation: "Frontend Developer", email: "frank@skote.com", projects: "132",
                skills: [
                    { name: "Html" },
                    { name: "Css" },
                    { name: "2 + more" },
                ]
            },
            {
                id: 3, img: avatar3, name: "Rafael Morales", designation: "Backend Developer", email: "Rafael@skote.com", projects: "1112",
                skills: [
                    { name: "Php" },
                    { name: "Java" },
                    { name: "Python" },
                ]
            },
            {
                id: 4, img: "Null", name: "Mark Ellison", designation: "Full Stack Developer", email: "mark@skote.com", projects: "121",
                skills: [
                    { name: "Ruby" },
                    { name: "Php" },
                    { name: "2 + more" },
                ]
            },
            {
                id: 5, img: avatar4, name: "Minnie Walter", designation: "Frontend Developer", email: "minnie@skote.com", projects: "145",
                skills: [
                    { name: "Html" },
                    { name: "Css" },
                    { name: "2 + more" },
                ]
            },
            {
                id: 6, img: avatar5, name: "Shirley Smith", designation: "UI/UX Designer", email: "shirley@skote.com", projects: "136",
                skills: [
                    { name: "Photoshop" },
                    { name: "UI/UX Designer" }
                ]
            },
            {
                id: 7, img: "Null", name: "John Santiago", designation: "Full Stack Developer", email: "john@skote.com", projects: "125",
                skills: [
                    { name: "Ruby" },
                    { name: "Php" },
                    { name: "2 + more" },
                ]
            },
            {
                id: 8, img: avatar7, name: "Colin Melton", designation: "Backend Developer", email: "colin@skote.com", projects: "136",
                skills: [
                    { name: "Php" },
                    { name: "Java" },
                    { name: "Python" },
                ]
            },
        ];

    const DefaultEvents = [{
        id: 1,
        title: 'Hey!',
        start: new Date().setDate(new Date().getDate() + 1),
        className: 'bg-warning text-white'
    },
        {
            id: 2,
            title: 'See John Deo',
            start: new Date(),
            end: new Date(),
            className: 'bg-success text-white'
        },
        {
            id: 3,
            title: 'Meet John Deo',
            start: new Date().setDate(new Date().getDate() + 8),
            className: 'bg-info text-white'
        },
        {
            id: 4,
            title: 'Buy a Theme',
            start: new Date().setDate(new Date().getDate() + 7),
            className: 'bg-primary text-white'
        }];

    const DefaultCategories = [
        {
            id: 1,
            title: 'New Theme Release',
            type: 'success'
        },
        {
            id: 2,
            title: 'My Event',
            type: 'info'
        },
        {
            id: 3,
            title: 'Meet Manager',
            type: 'warning'
        },
        {
            id: 4,
            title: 'Report Error',
            type: 'danger'
        },
    ];
    const event1= { id: 0, title: "", title_category: "", start: "", className: "", category: "", event_category: "" };
    const [calendarEvents, setCalendarEvents] = useState(DefaultEvents);
    const [categories, setCategories] = useState(DefaultCategories);
    const [modal, setModal] = useState(false);
    const [modal1, setModal1] = useState(false);
    const [modalcategory, setModalcategory] = useState(false);
    const [event, setEvent] = useState(event1);
    const [selectedDay, setSelectedDay] = useState(0);
    const title_category = false;

    const calendarComponentRef = React.createRef();
    

    useEffect(() => {
        new Draggable(document.getElementById("external-events"), {
            itemSelector: '.external-event',
        });
    });

    /**
     * Handling the modal state
     */
    function toggle() {
        setModal(!modal)
    }

    function toggle1() {
        setModal1(!modal1)
    }

    function togglecategory() {
        setModalcategory(!modalcategory)
    }

    /**
     * Handling date click on calendar
     */
    const handleDateClick = (arg) => {
        setSelectedDay(arg);
        toggle();
    }

    /**
     * Handling click on event on calendar
     */
    const handleEventClick = (arg) => {
        const eventNew = arg.event;

        const event_tmp = { id: eventNew.id, title: eventNew.title, title_category: eventNew.title_category, start: eventNew.start, className: eventNew.classNames, category: eventNew.classNames[0], event_category: eventNew.classNames[0] };

        setEvent(event_tmp);
        toggle1();
    }

    /**
     * Handling submit event on event form
     */
    const handleValidEventSubmit = (e, values) => {
        var newEvent = {};


        newEvent = {
            id: calendarEvents.length + 1,
            title: values['title'],
            start: selectedDay ? selectedDay.date : new Date(),
            className: values.category + ' text-white'
        };


        // save new event
        setCalendarEvents(calendarEvents.concat(newEvent));
        setSelectedDay(null);

        toggle();
    }

    const handleValidEventSubmitEvent = (e, values) => {
        var newEvent = {};
        newEvent = { id: event.id, title: values.title, classNames: values.category + ' text-white', start: event.start };
        //first, remove array item, which we want to edit
        let filteredArray = calendarEvents.filter(item => item.id + "" !== event.id + "");

        //then concat update item details
        let NewArray = filteredArray.concat(newEvent);

        //store to state
        setCalendarEvents(NewArray);
        setEvent(null);
        setSelectedDay(null);

        toggle1();
    }

    const handleValidEventSubmitcategory = (e, values) => {

        var newEvent = {};

        newEvent = {
            id: calendarEvents.length + 1,
            title: values['title_category'],
            type: values.event_category
        };
        // categories.concat(newEvent);
        setCategories(categories.concat(newEvent));

        togglecategory();
    }

    /**
     * On calendar drop event
     */
    const onDrop = (event) => {
        const draggedEl = event.draggedEl;

        var newEvent = {
            id: calendarEvents.length + 1,
            title: draggedEl.innerText,
            start: event.date,
            className: draggedEl.getAttribute('data-type') + ' text-white'
        };

        // save new event
        setCalendarEvents(calendarEvents.concat(newEvent));
    }


    return (
             <React.Fragment>
                <div className="page-content">
                    <Container fluid>

                        {/* Render Breadcrumbs */}
                        <Breadcrumbs title="Contacts" breadcrumbItem="Users List" />
                        <Card>
                            <CardBody>
                                <Row>
                                    <Col lg={3}>
                                        <Button color="primary" className="font-16 btn-block" onClick={() => togglecategory() }>
                                            <i className="mdi mdi-plus-circle-outline"></i> Create New Event
                                        </Button>

                                        <div id="external-events" className="mt-3">
                                            <p className="text-muted">Drag and drop your event or click in the calendar</p>

                                            {categories.map((category, i) => {
                                                return <Alert color={category.type}>{category.title} </Alert>
                                            })}
                                        </div>
                                        </Col>
                                    <Col className="col-lg-3">
                                        <div className="table-responsive">
                                            <Table className="table-centered table-nowrap table-hover">
                                                <thead className="thead-light">
                                                <tr>
                                                    <th scope="col" style={{ width: "70px" }}>#</th>
                                                    <th scope="col">Name</th>
                                                </tr>
                                                </thead>
                                                <tbody>
                                                {
                                                    employees.map((user, i) =>
                                                        <tr key={"_user_" + i} >
                                                            <td>
                                                                {
                                                                    user.img === "Null"
                                                                        ? <div className="avatar-xs">
                                                                                <span className="avatar-title rounded-circle">
                                                                                    {user.name.charAt(0)}
                                                                                </span>
                                                                        </div>
                                                                        : <div>
                                                                            <img className="rounded-circle avatar-xs" src={user.img} alt="" />
                                                                        </div>
                                                                }

                                                            </td>
                                                            <td>
                                                                <h5 className="font-size-14 mb-1"><Link to="#" className="text-dark">{user.name}</Link></h5>
                                                                <p className="text-muted mb-0">{user.designation}</p>
                                                            </td>
                                                        </tr>
                                                    )
                                                }
                                                </tbody>
                                            </Table>
                                        </div>

                                    </Col>
                                    <Col className="col-lg-6">
                                        {/* fullcalendar control */}
                                        <FullCalendar ref={calendarComponentRef} defaultView="dayGridMonth" plugins={[BootstrapTheme, dayGridPlugin, interactionPlugin]}
                                                      slotDuration={'00:15:00'}
                                                      minTime={'08:00:00'}
                                                      maxTime={'19:00:00'}
                                                      handleWindowResize={true}
                                                      themeSystem="bootstrap"
                                                      header={{
                                                          left: 'prev,next today',
                                                          center: 'title',
                                                          right: 'dayGridMonth,dayGridWeek,dayGridDay'
                                                      }}
                                                      events={calendarEvents}
                                                      editable={true}
                                                      droppable={true}
                                                      eventLimit={true}
                                                      selectable={true}
                                                      dateClick={handleDateClick}
                                                      eventClick={handleEventClick}
                                                      drop={onDrop}
                                                      id="calendar" />

                                        <button onClick={() => togglecategory() }
                                                className="btn btn-secondary float-right btn-lg waves-effect btn btn-secondary">
                                            Neuen Termin anlegen
                                        </button>
                                        {/* New event modal */}
                                        <Modal isOpen={modal} toggle={() => toggle()} className="">
                                            <ModalHeader toggle={() => toggle()} tag="h4">
                                                Add Event
                                            </ModalHeader>
                                            <ModalBody>
                                                <AvForm onValidSubmit={handleValidEventSubmit}>
                                                    <Row form>
                                                        <Col className="col-12">
                                                            <AvField name="title" label="Event Name" type="text" errorMessage="Invalid name" validate={{
                                                                required: { value: true }
                                                            }} value={event ? event.title : ''} />
                                                        </Col>
                                                        <Col className="col-12">
                                                            <AvField type="select" name="category" label="Select Category"
                                                                     value={event ? event.category : 'bg-primary'}>
                                                                <option value="bg-danger">Danger</option>
                                                                <option value="bg-success">Success</option>
                                                                <option value="bg-primary">Primary</option>
                                                                <option value="bg-info">Info</option>
                                                                <option value="bg-dark">Dark</option>
                                                                <option value="bg-warning">Warning</option>
                                                            </AvField>
                                                        </Col>
                                                    </Row>
                                                    <Row>
                                                        <Col>
                                                            <div className="text-right">
                                                                <button type="button" className="btn btn-light mr-2" onClick={() => toggle()}>Close</button>
                                                                <button type="submit" className="btn btn-success save-event">Save</button>
                                                            </div>
                                                        </Col>
                                                    </Row>
                                                </AvForm>
                                            </ModalBody>
                                        </Modal>

                                        {/* edit event modal */}
                                        <Modal isOpen={modal1} toggle={() => toggle1()} className="">
                                            <ModalHeader toggle={() => toggle1()} tag="h4">
                                                Edit Event
                                            </ModalHeader>
                                            <ModalBody>
                                                <AvForm onValidSubmit={handleValidEventSubmitEvent}>
                                                    <Row form>
                                                        <Col className="col-12">
                                                            <AvField name="title" label="Event Name" type="text" errorMessage="Invalid name" validate={{
                                                                required: { value: true }
                                                            }} value={event ? event.title : ''} />
                                                        </Col>
                                                        <Col className="col-12">
                                                            <AvField type="select" name="category" label="Select Category"
                                                                     value={event ? event.category : 'bg-primary'}>
                                                                <option value="bg-danger">Danger</option>
                                                                <option value="bg-success">Success</option>
                                                                <option value="bg-primary">Primary</option>
                                                                <option value="bg-info">Info</option>
                                                                <option value="bg-dark">Dark</option>
                                                                <option value="bg-warning">Warning</option>
                                                            </AvField>
                                                        </Col>
                                                    </Row>
                                                    <Row>
                                                        <Col>
                                                            <div className="text-right">
                                                                <button type="button" className="btn btn-light mr-2" onClick={() => toggle()}>Close</button>
                                                                <button type="submit" className="btn btn-success save-event">Save</button>
                                                            </div>
                                                        </Col>
                                                    </Row>
                                                </AvForm>
                                            </ModalBody>
                                        </Modal>

                                        <Modal isOpen={modalcategory} toggle={() => togglecategory()} className="">
                                            <ModalHeader toggle={() => togglecategory()} tag="h4">
                                                Add a category
                                            </ModalHeader>
                                            <ModalBody>
                                                <AvForm onValidSubmit={handleValidEventSubmitcategory}>
                                                    <Row form>
                                                        <Col className="col-12">
                                                            <AvField name="title_category" label="Category Name" type="text" errorMessage="Invalid name" validate={{
                                                                required: { value: true }
                                                            }} value={title_category ? event.title_category : ''} />
                                                        </Col>
                                                        <Col className="col-12">
                                                            <AvField type="select" name="event_category" label="Choose Category Color"
                                                                     value={event ? event.event_category : 'bg-primary'}>
                                                                <option value="bg-danger">Danger</option>
                                                                <option value="bg-success">Success</option>
                                                                <option value="bg-primary">Primary</option>
                                                                <option value="bg-info">Info</option>
                                                                <option value="bg-dark">Dark</option>
                                                                <option value="bg-warning">Warning</option>
                                                            </AvField>
                                                        </Col>
                                                    </Row>
                                                    <Row>
                                                        <Col>
                                                            <div className="text-right">
                                                                <button type="button" className="btn btn-light mr-2" onClick={() => togglecategory()}>Close</button>
                                                                <button type="submit" className="btn btn-success save-event">Save</button>
                                                            </div>
                                                        </Col>
                                                    </Row>
                                                </AvForm>
                                            </ModalBody>
                                        </Modal>
                                    </Col>
                                </Row>
                            </CardBody>
                        </Card>
                    </Container>
                </div>
            </React.Fragment>
          );
    }
        
export default ContactsList;

任何提示或帮助将不胜感激 - 提前致谢!

几件事:

  • 您不应在函数本身中获取数据 - 这将在每次组件呈现时触发获取。通常,您希望在组件首次呈现时开始获取:
useEffect(() => {
  fetchData().then(response => {
    const employees = JSON.parse(response)
    setEmployees(employees)
  })
}, [])

另见这个问题:

现在我们有了正确的方法来获取数据,我们开始讨论另一个问题 - what to set the state to by definition。也就是说,如何初始化数据。人们可能会告诉你它可以是任何东西,但实际上,如果你正在使用一个数组(你正在迭代 employees 对象,所以我假设它是一个数组),最好用一个空数组初始化它.这样类型就不会改变,下面的 JSX 不需要额外的条件逻辑来处理不同类型的员工。

const [employees, setEmployees] = useState([])

我通常先调用useState,然后再调用useEffect。实际上,如果你交换它们,不确定它是否会破裂。所以总代码为:


const fetchData = async () => {
    const res = await fetch('https://swapi.dev/api/people/')
    const json = await res.json()
    return json.result
}

const ContactsList = props => {
  const [employees, setEmployees] = useState([])

  useEffect(() => {
    fetchData().then(employees => {
      setEmployees(employees)
    })
  }, [])

  return (
    <div>
      {employees.map(employee => <div key={employee.id}>{employee.name}</div>)}
    </div>
  )
}

更笼统的说明:

  • 你的组件很大。 React 的美妙之处在于你可以将它分成子组件。这不仅对您自己是个好习惯,而且其他 Whosebug 用户也更容易理解您的问题。只在组件中保留真正需要的东西。