grahql极简入门教程(基于react+graphql-yoga+urql)③

407 阅读3分钟

本文是graphql极简入门教程的第三篇,本篇主要讲述在react中对接graphql的新增和查询操作

graphql极简入门教程目录:

👉🏻点击进入本教程github仓库

在react中展示数据

目前创建和查询的数据,都局限在playground中。接下来将要把后端的数据,真实的展示在前端中。

首先在src/components目录下,创建Link.js文件,在此文件中编写链接项的展示组件

// 文件路径:src/components/Link.js
import React from 'react';
//①
import {timeDifferenceForDate} from '../utils';

const Link = (props) => {
    const {link} = props;

    return (
        <div className="ml1">
            <div>
                {link.description} ({link.url})
            </div>
            {(
                <div className="f6 lh-copy gray">
                    {timeDifferenceForDate(link.createdAt)}
                </div>
            )}
        </div>
    );
};

export default Link;

回忆一下hackernews对于创建时间展示的处理:

image-20230204003223534

在这里展示风格为58 minutes ago,因此在下面将会创建一个timeDifferenceForDate方法处理createdAt字段。在①中提前先引入该方法

src目录下创建utils.js文件:

// 文件路径:src/utils.js
function timeDifference(current, previous) {
    const milliSecondsPerMinute = 60 * 1000;
    const milliSecondsPerHour = milliSecondsPerMinute * 60;
    const milliSecondsPerDay = milliSecondsPerHour * 24;
    const milliSecondsPerMonth = milliSecondsPerDay * 30;
    const milliSecondsPerYear = milliSecondsPerDay * 365;

    const elapsed = current - previous;

    if (elapsed < milliSecondsPerMinute / 3) {
        return 'just now';
    }

    if (elapsed < milliSecondsPerMinute) {
        return 'less than 1 minute ago';
    } else if (elapsed < milliSecondsPerHour) {
        return (
            Math.round(elapsed / milliSecondsPerMinute) +
            ' minutes ago'
        );
    } else if (elapsed < milliSecondsPerDay) {
        return (
            Math.round(elapsed / milliSecondsPerHour) + ' hours ago'
        );
    } else if (elapsed < milliSecondsPerMonth) {
        return (
            Math.round(elapsed / milliSecondsPerDay) + ' days ago'
        );
    } else if (elapsed < milliSecondsPerYear) {
        return (
            Math.round(elapsed / milliSecondsPerMonth) + ' months ago'
        );
    } else {
        return (
            Math.round(elapsed / milliSecondsPerYear) +
            ' years ago'
        );
    }
}

export function timeDifferenceForDate(date) {
    const now = new Date().getTime();
    const updated = new Date(date).getTime();
    return timeDifference(now, updated);
}

接下来,在src/components目录下,创建LinkList.js文件,在此文件中编写链接列表组件:

import React from 'react';
import Link from './Link';
import {useQuery} from "urql";

// ①
const feedQuery = `
    query {
        feed {
            links {
                id
                createdAt
                url
                description
            }
        }
    }
`;

const LinkList = () => {
    // ②
    const [result] = useQuery({
        query: feedQuery,
    });

    // ③
    const { data, fetching, error } = result;
    return (
        <div>
            {fetching && <p>Loading...</p>}
            {error && <pre>{JSON.stringify(error, null, 2)}</pre>}
            {data && (
                data.feed.links.map((link) => (
                    <Link key={link.id} link={link} />
                ))
            )}
        </div>
    );
};

export default LinkList;

在①中,定义了一个查询语句,与之前在playground中传入的语句一致。

查找内容

在②中,将查询语句作为参数传给useQuery钩子,并解构出返回的结果result

在③中,我们解构出

  • data: graphql返回的查询结果数据
  • fetching:当前是否正在请求后端接口
  • error:错误信息

接下来,打开http://localhost:3000页面就可以看到,之前写入的两条链接数据了

简单列表数据

在react中新建数据

要创建数据需要先有一个表单,因此在src/components目录下,创建CreateLink.js文件,在此文件中编写创建链接的Form表单:

import React, { useState } from 'react';

const CreateLink = () => {
    const [formState, setFormState] = useState({
        description: '',
        url: ''
    });

    return (
        <div>
            <form
                onSubmit={(e) => {
                    e.preventDefault();
                }}
            >
                <div className="flex flex-column mt3">
                    <input
                        className="mb2"
                        value={formState.description}
                        onChange={(e) =>
                            setFormState({
                                ...formState,
                                description: e.target.value
                            })
                        }
                        type="text"
                        placeholder="A description for the link"
                    />
                    <input
                        className="mb2"
                        value={formState.url}
                        onChange={(e) =>
                            setFormState({
                                ...formState,
                                url: e.target.value
                            })
                        }
                        type="text"
                        placeholder="The URL for the link"
                    />
                </div>
                <button type="submit">Submit</button>
            </form>
        </div>
    );
};

export default CreateLink;

接下来,需要编写创建链接的语句,请注意这里与之前在playground中的写法有一些不同,请注意两者的差别:

react中的语句:

const createLinkMutation = `
  mutation PostMutation(
    $description: String!
    $url: String!
  ) {
    post(description: $description, url: $url) {
      id
      createdAt
      url
      description
    }
  }
`;

playground中的语句

更多返回值示例

可以看到在react中,mutation的语句更加类似于在写typescript时,对于函数类型的定义。在仔细观察之后,不难学会。

接下来,就需要urql中的useMutation钩子,来做相关的调用工作

import {useMutation} from "urql";

const [createLinkResult, createLink] = useMutation(createLinkMutation);

const { data, fetching, error } = createLinkResult;

这里可以看到,useMutationuseQuery返回的result数据结构是一致的

接下来,需要将上面的这些内容都添加src/components/CreateLink.js文件中:

import React, { useState } from 'react';
import {useMutation} from "urql";

export const createLinkMutation = `
  mutation PostMutation(
    $description: String!
    $url: String!
  ) {
    post(description: $description, url: $url) {
      id
      createdAt
      url
      description
    }
  }
`;

const CreateLink = () => {
    const [formState, setFormState] = useState({
        description: '',
        url: ''
    });

    const [createLinkResult, createLink] = useMutation(createLinkMutation);

    const { data, fetching, error } = createLinkResult;

    return (
        <div>
            <form
                onSubmit={(e) => {
                    e.preventDefault();
                    createLink(formState);
                }}
            >
                <div className="flex flex-column mt3">
                    <input
                        className="mb2"
                        value={formState.description}
                        onChange={(e) =>
                            setFormState({
                                ...formState,
                                description: e.target.value
                            })
                        }
                        type="text"
                        placeholder="A description for the link"
                    />
                    <input
                        className="mb2"
                        value={formState.url}
                        onChange={(e) =>
                            setFormState({
                                ...formState,
                                url: e.target.value
                            })
                        }
                        type="text"
                        placeholder="The URL for the link"
                    />
                </div>
                <button disabled={fetching} type="submit">Submit {fetching && '(sending...)'}</button>
            </form>
        </div>
    );
};

export default CreateLink;

并且在src/components/App.js中引入该组件:

import React, { Component } from 'react';
import LinkList from './LinkList';
import CreateLink from "./CreateLink";

class App extends Component {
  render() {
    return (
        <>
          <CreateLink />
          <LinkList />
        </>
    );
  }
}

export default App;

此时,你在http://localhost:3000页面中,就可以直接创建链接了

在react中创建链接

为了测试笔者添加了两次,因此添加后的结果如下:

创建结果

至此,我们的前后端联调已经完成!现在你已经可以在前端进行创建和查询操作了( ^▽^ )✌🏻

下一章节将会为react前端添加路由,并实现搜索功能

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 3 天,点击查看活动详情