LoginSignup
0
0

More than 1 year has passed since last update.

React Query使い方忘却録

Last updated at Posted at 2022-06-26

内容

React Queryの学習用メモとしてまとめる。
※パフォーマンスは未考慮。
APIはjsonplaceholderを使用して、実装を確認。

開発環境

PC:macOS Monterey(Intel)
エディター:Visual Studio Code

パッケージマネージャー: yarn
パッケージ:
react: 18.1.0
react-query: 3.39.1
typescript: 4.6.4

API

useQuery

useQueryは一意のqueryKeyに基づいて、クエリを管理することができる。

useQuery.d.tsには以下の3つのuseQuery関数が記載されている。(一部省略)

useQuery.d.ts
useQuery(options);
useQuery(queryKey, options?);
useQuery(queryKey, queryFn, options?);

type.d.tsファイルより、
queryKeyは文字列、配列で指定できる。
queryFnの戻り値は任意の型かPromiseの任意の型。
optionsはこちらを参照。

type.d.ts
export declare type QueryKey = string | readonly unknown[];
export declare type QueryFunction<T = unknown, TQueryKey extends QueryKey = QueryKey> = (context: QueryFunctionContext<TQueryKey>) => T | Promise<T>;

useQueryサンプルコード

コードはこちら
useTodoQuery.ts
// jsonplaceholderのtodosの型を定義
type TodoType = {
  userId: Number,
  id: Number,
  title: String,
  completed: boolean,
}

// queryFn
const fetchTodosQueryFn = async () => {
  const result = await fetch('https://jsonplaceholder.typicode.com/todos');

  if (result.status !== 200) {
    throw new Error('fetch Error')
  }
  return result.json();
}

// useQUery(queryKey='todos' , queryFn=fetchTodosQueryFn)
export const fetchTodoList = () => {
  return useQuery<TodoType[], Error>(
    'todos',
    fetchTodosQueryFn,
  );

    // オブジェクトとして書くことも可能
    // return useQuery<TodoType[], Error>(
    //   {
    //     queryKey: 'todos',
    //     queryFn: fetchTodosQueryFn,
    //   }
    // );
}
Todos.tsx
import { fetchTodoList } from 'useTodoQuery';

export const Todos = () => {
  const { isLoading, isError, error, data } = fetchTodoList();

  if (isLoading) {
    return (
      <>
        'Loading...'
      </>
    );
  }

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

  if (!data) {
    return (
      <>
        none data
      </>
    );
  }

  return (
    <ul>
      {data.map(todo => (
        <li key={todo.id.toString()}>{todo.title}</li>
      ))}
    </ul>
  );
};

以下のように取得したtodoが表示されていることが確認できる。
スクリーンショット 2022-06-26 16.33.53.png

useMutation

useMutationはデータの作成/更新/削除時に使用される。

useMutation.d.tsには以下の4つのuseMutation関数が記載されている。(一部省略)

useMutation.d.ts
useMutation(options);
useMutation(mutationFn, options?); 
useMutation(mutationKey, options?);
useMutation(mutationKey, mutationFn?, options?);

useMutationサンプルコード

コードはこちら
useTodoQuery.ts
// jsonplaceholderのtodosの型を定義
type TodoType = {
  userId: Number,
  id: Number,
  title: String,
  completed: boolean,
}

const createTodoQueryFn = (body: NewTodoType) => axios.post<NewTodoType>('https://jsonplaceholder.typicode.com/todos', body).then(res => res.data);

const createTodoWithMutation = () => useMutation<NewTodoType, Error, NewTodoType>(
  'newTodo',
  async (body: NewTodoType) => {
    const result = await createTodoQueryFn(body);
    return result;
  },
  {
    onSuccess: (todo) => {
      console.log('Mutation', todo);
    },
    onError(error, variables, context) {
      console.log('error', error.message);
    },
  }
);
TodoForm.tsx
import { Button, Box, Container, TextField, Typography } from '@mui/material';
import { SubmitHandler, useForm } from 'react-hook-form';
import * as yup from "yup";
import { yupResolver } from '@hookform/resolvers/yup';

import { useTodoList } from 'useTodoList';

// バリデーションルール
let todoSchema = yup.object({
  id: yup.number().default(1),
  title: yup.string().required('タイトルを入力してください'),
  completed: yup.boolean().default(false),
});

export const TodoInputForm = () => {
  const { createTodo, createTodoWithMutation } = useTodoList();

  const mutation = createTodoWithMutation();

  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<TodoType>({ resolver: yupResolver(todoSchema) })

  const onSubmit: SubmitHandler<TodoType> = async (data) => {
    mutation.mutate(
      {
        id: data.id,
        title: data.title,
      });
  };

  return (
    <Container maxWidth="sm" sx={{ p: 5 }}>
      <Typography variant='h1' >Todo List</Typography>

      {mutation.isLoading ?
        <>
          作成中...
        </>
        :
        <Box
          sx={{
            display: 'flex',
            justifyContent: 'space-around',
          }}
        >
          <TextField
            required
            label="タイトル"
            type="title"
            {...register('title')}
            error={'title' in errors}
            helperText={errors.title?.message}
          />
          <Button
            color="primary"
            variant="contained"
            size="large"
            onClick={handleSubmit(onSubmit)}
          >
            新規作成
          </Button>
        </Box>
      }
    </Container>
  );
};

参考記事

公式 React Query

JSONPlaceholider

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0