skip to Main Content

I’m developing an application using a GraphQL client and React. In the main directory, I have a section where events are listed, and in the …/new directory, I have a form to add new events. When I add an event using the GraphQL Playground or by connecting to the …/new directory in a new tab, the list on the main page gets updated. However, if I use React Router to navigate to the …/new directory and add an event, the event list on the main page does not get updated."

EventList.js

import React, { useEffect } from "react";
import { useQuery } from "@apollo/client";
import { EVENT_SUBSCRIPTION, GET_EVENTS } from "./queries";
import { List, Divider } from "antd";
import InfiniteScroll from "react-infinite-scroll-component";
import { Link } from "react-router-dom";
import styles from "./styles.module.css";
import Loading from "../../components/Loading";
import EventCounter from "../../components/EventCounter";

function EventList() {
    const { loading, error, data, subscribeToMore } = useQuery(GET_EVENTS);

    useEffect(() => {
        subscribeToMore({
            document: EVENT_SUBSCRIPTION,
            updateQuery: (prev, { subscriptionData }) => {
                console.log(prev, subscriptionData);
                if (!subscriptionData.data) return prev;
                return {
                    events: [...prev.events, subscriptionData.data.eventCreated],
                };
            },
        });
    }, [subscribeToMore]);

    if (loading) {
        return <Loading />;
    }

    if (error) {
        return <div>Error: {error.message}</div>;
    }

    return (
        <>
            <div className="counter">
                <EventCounter />
            </div>

            <div className={styles.scrollableDiv} id="scrollableDiv">
                <List>
                    <InfiniteScroll dataLength={data.events.length} scrollableTarget="scrollableDiv" endMessage={<Divider plain>It is all, nothing more 🤐</Divider>}>
                        <List
                            dataSource={data.events}
                            renderItem={(item) => (
                                <List.Item key={item.id}>
                                    <List.Item.Meta
                                        title={
                                            <Link className={styles.listItemTitle} to={`/event/${item.id}`}>
                                                {item.title}
                                            </Link>
                                        }
                                        description={
                                            <Link className={styles.listItemDesc} to={`/event/${item.id}`}>
                                                {item.desc}
                                            </Link>
                                        }
                                    />
                                    <div className={styles.date}>{`${item.date} / ${item.from}-${item.to}`}</div>
                                </List.Item>
                            )}></List>
                    </InfiniteScroll>
                </List>
            </div>
        </>
    );
}

export default EventList;

FormComponent.js

import React from "react";
import { Button, DatePicker, Form, Input, Row, Select, TimePicker } from "antd";
import { useMutation, useQuery } from "@apollo/client";
import moment from "moment";
import styles from "./style.module.css";
import { CREATE_EVENT, GET_LOCATIONS, GET_USERS } from "./queries";

function FormComponent() {
    const [addEvent, { data, loading, error }] = useMutation(CREATE_EVENT);

    const { loading: locationsLoading, error: locationsError, data: locationsData } = useQuery(GET_LOCATIONS);
    const locationsArray = [];
    if (!locationsLoading && !locationsError && locationsData) {
        locationsData.locations.forEach((item) => {
            const data = {
                value: item.id,
                label: item.name,
                title: "location_id",
            };
            locationsArray.push(data);
        });
    }

    const { loading: userLoading, error: userError, data: userData } = useQuery(GET_USERS);
    const usersArray = [];
    if (!userLoading && !userError && userData) {
        userData.users.forEach((item) => {
            const data = {
                value: item.id,
                label: item.username,
                title: "user_id",
            };
            usersArray.push(data);
        });
    }

    const [form] = Form.useForm();

    const disabledDate = (current) => {
        return current && current <= moment().startOf("day");
    };

    const handleFormSubmit = async (values) => {
        const data = {
            title: values.title,
            desc: values.desc,
            date: `${values.date.$y}-${values.date.$M + 1}-${values.date.$D}`,
            from: `${values.hours[0].$H < 9 ? "0" + values.hours[0].$H : values.hours[0].$H}:${values.hours[0].$m < 9 ? "0" + values.hours[0].$m : values.hours[0].$m}`,
            to: `${values.hours[1].$H < 9 ? "0" + values.hours[1].$H : values.hours[1].$H}:${values.hours[1].$m < 9 ? "0" + values.hours[1].$m : values.hours[1].$m}`,
            location_id: values.location_id,
            user_id: values.user_id,
        };
        await addEvent({
            variables: {
                data: data,
            },
            onCompleted: form.resetFields(),
        });
    };

    return (
        <Row>
            <Form className={styles.form} labelCol={{ span: 4 }} wrapperCol={{ span: 24 }} form={form} onFinish={handleFormSubmit}>
                <Form.Item label="Title" name="title" required rules={[{ required: true, message: "Please enter title" }]}>
                    <Input placeholder="Please enter title" />
                </Form.Item>
                <Form.Item label="Description" name="desc" required rules={[{ required: true, message: "Please enter description" }]}>
                    <Input.TextArea placeholder="Please enter description" />
                </Form.Item>
                <Form.Item label="Date" name="date" required rules={[{ required: true, message: "Please enter date" }]}>
                    <DatePicker placeholder="Please select a date" style={{ width: "100%" }} disabledDate={disabledDate} />
                </Form.Item>
                <Form.Item name="hours" label="Event Hours" required>
                    <TimePicker.RangePicker style={{ width: "100%" }} placeholder={["Select start time", "Select end time"]} format={"HH:mm"} />
                </Form.Item>
                <Form.Item label="Location" name="location_id" required rules={[{ required: true, message: "Please select a location" }]}>
                    <Select placeholder="Please select a location" options={locationsArray} />
                </Form.Item>
                <Form.Item label="User" name="user_id" required rules={[{ required: true, message: "Please select a user" }]}>
                    <Select placeholder="Please select a user" options={usersArray} />
                </Form.Item>
                <Form.Item>
                    <Button type="primary" htmlType="submit">
                        Submit
                    </Button>
                </Form.Item>
            </Form>
        </Row>
    );
}

export default FormComponent;

2

Answers


  1. Chosen as BEST ANSWER

    i solved the problem like this thank you very much

    await addEvent({
                    variables: {
                        data: values,
                    },
                    update: (cache, { data: { addEvent} }) => {
                        const events = cache.readQuery({ query: GET_EVENTS });
                        cache.writeQuery({
                            query: GET_EVENTS,
                            data: { events: [addEvent, ...events.events] },
                        });
                    },
                    onCompleted: navigate("/"),
                });
    

  2. You can use Apollo Client’s Cache Update.
    When you add an event using the addEvent mutation in the FormComponent, you can manually update the Apollo Client cache to include the new event, so when you navigate back to the EventList component, it will re-render with the updated data.

    await addEvent({
        variables: {
            data: data,
        },
        update: (cache, { data: { addEvent } }) => {
            const { events } = cache.readQuery({ query: GET_EVENTS });
            cache.writeQuery({
                query: GET_EVENTS,
                data: { events: events.concat([addEvent]) },
            });
        },
        onCompleted: form.resetFields(),
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search