健康に反応する精神25


#25自信を持て!


userasync custom hookの作成と使用


私たちはデータを申請するたびに更新員になります.これは面倒なことです.毎回重複するコードを記述するよりも、カスタム・ホームページを作成して、リクエスト・ステータス管理ロジックを簡単に再利用する方法を理解します.
まず、srcディレクトリでasyncを使用します.jsファイルを生成し、コードを次のように記述します.

useAsync.js

import { useReducer, useEffect } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'LOADING':
      return {
        loading: true,
        data: null,
        error: null
      };
    case 'SUCCESS':
      return {
        loading: false,
        data: action.data,
        error: null
      };
    case 'ERROR':
      return {
        loading: false,
        data: null,
        error: action.error
      };
    default:
      throw new Error(`Unhandled action type: ${action.type}`);
  }
}

function useAsync(callback, deps = []) {
  const [state, dispatch] = useReducer(reducer, {
    loading: false,
    data: null,
    error: false
  });

  const fetchData = async () => {
    dispatch({ type: 'LOADING' });
    try {
      const data = await callback();
      dispatch({ type: 'SUCCESS', data });
    } catch (e) {
      dispatch({ type: 'ERROR', error: e });
    }
  };

  useEffect(() => {
    fetchData();
    // eslint 설정을 다음 줄에서만 비활성화
    // eslint-disable-next-line
  }, deps);

  return [state, fetchData];
}

export default useAsync;
上のコードから見ると、userasync関数は2つのパラメータを受け入れます.
最初のパラメータはAPI要求を開始するコールバック関数であり、2番目のパラメータはdepsであり、このdeps値はこの関数で使用されるuserEffectのdepsに設定される.
後で使用する非同期関数にパラメータが必要で、パラメータが変更されたときに新しいデータをロードしたい場合は、上記を使用します.
既定値は[](括弧)です.つまり、構成部品が最初にレンダリングされたときにのみAPIが呼び出されます.
その結果、このHookが返す値は、要求関連状態とfetchData関数です.これでfetchData関数を返し、後で簡単にデータを再ロードできます.
今から私たちが書いたこのHookを使いましょう!

Users.js

import React from 'react';
import axios from 'axios';
import useAsync from './useAsync';

// useAsync 에서는 Promise 의 결과를 바로 data 에 담기 때문에,
// 요청을 한 이후 response 에서 data 추출하여 반환하는 함수를 따로 만들었습니다.
async function getUsers() {
  const response = await axios.get(
    'https://jsonplaceholder.typicode.com/users'
  );
  return response.data;
}

function Users() {
  const [state, refetch] = useAsync(getUsers, []);

  const { loading, data: users, error } = state; // state.data 를 users 키워드로 조회

  if (loading) return <div>로딩중..</div>;
  if (error) return <div>에러가 발생했습니다</div>;
  if (!users) return null;
  return (
    <>
      <ul>
        {users.map(user => (
          <li key={user.id}>
            {user.username} ({user.name})
          </li>
        ))}
      </ul>
      <button onClick={refetch}>다시 불러오기</button>
    </>
  );
}

export default Users;
コードを保存して、正常に動作しているかどうかを確認します.
コードは以前よりきれいに見えて、また使いやすいです.

後でデータをロード


ユーザコンポーネントは、最初のレンダリングコンポーネントからAPIを要求することを知る必要がある.特定のボタンを押したときだけAPIを要求したい場合、どうすればいいですか?
例えば、HTTPメソッド(POST、DELETE、PUT、PATCHなど)を使用すると、必要なときにAPIを呼び出すだけなので、好きなように要求できる機能が必要となる.
実施してみましょう.
userasyncでは、skipを次のように3番目のパラメータとして使用します.

useAsync.js

import { useReducer, useEffect } from 'react';

function reducer(state, action) {
  switch (action.type) {
    case 'LOADING':
      return {
        loading: true,
        data: null,
        error: null
      };
    case 'SUCCESS':
      return {
        loading: false,
        data: action.data,
        error: null
      };
    case 'ERROR':
      return {
        loading: false,
        data: null,
        error: action.error
      };
    default:
      throw new Error(`Unhandled action type: ${action.type}`);
  }
}

function useAsync(callback, deps = [], skip = false) {
  const [state, dispatch] = useReducer(reducer, {
    loading: false,
    data: null,
    error: false
  });

  const fetchData = async () => {
    dispatch({ type: 'LOADING' });
    try {
      const data = await callback();
      dispatch({ type: 'SUCCESS', data });
    } catch (e) {
      dispatch({ type: 'ERROR', error: e });
    }
  };

  useEffect(() => {
    if (skip) return;
    fetchData();
    // eslint 설정을 다음 줄에서만 비활성화
    // eslint-disable-next-line
  }, deps);

  return [state, fetchData];
}

export default useAsync;
skipパラメータのデフォルト値としてfalseを設定し、trueの場合はuserEffectでアクションを実行しません.
これにより、Users構成部品が変更されます.

Users.js

import React from 'react';
import axios from 'axios';
import useAsync from './useAsync';

// useAsync 에서는 Promise 의 결과를 바로 data 에 담기 때문에,
// 요청을 한 이후 response 에서 data 추출하여 반환하는 함수를 따로 만들었습니다.
async function getUsers() {
  const response = await axios.get(
    'https://jsonplaceholder.typicode.com/users'
  );
  return response.data;
}

function Users() {
  const [state, refetch] = useAsync(getUsers, [], true);

  const { loading, data: users, error } = state; // state.data 를 users 키워드로 조회

  if (loading) return <div>로딩중..</div>;
  if (error) return <div>에러가 발생했습니다</div>;
  if (!users) return <button onClick={refetch}>불러오기</button>;
  return (
    <>
      <ul>
        {users.map(user => (
          <li key={user.id}>
            {user.username} ({user.name})
          </li>
        ))}
      </ul>
      <button onClick={refetch}>다시 불러오기</button>
    </>
  );
}

export default Users;
Usersはtrueをusersyncの3番目のパラメータに入れます!ユーザーの場合、[ロード](Load)ボタンがレンダリングされます.

出典:ベロフトとのモダン反応
正常に動作していることを確認できます.

APIにパラメータが必要な場合


今回は、APIをリクエストする際に、パラメータが必要な場合はどうすればいいのかを調べてみましょう!
Userというコンポーネントを作成し、id値をpropsとして取得します.
https://jsonplaceholder.typicode.com/users/1
以上のようにして,最後にidリクエストAPIを加える.
srcディレクトリのUser.jsを生成すると,以下のようにコードを記述することができる.

User.js

import React from 'react';
import axios from 'axios';
import useAsync from './useAsync';

async function getUser(id) {
  const response = await axios.get(
    `https://jsonplaceholder.typicode.com/users/${id}`
  );
  return response.data;
}

function User({ id }) {
  const [state] = useAsync(() => getUser(id), [id]);
  const { loading, data: user, error } = state;

  if (loading) return <div>로딩중..</div>;
  if (error) return <div>에러가 발생했습니다</div>;
  if (!user) return null;

  return (
    <div>
      <h2>{user.username}</h2>
      <p>
        <b>Email:</b> {user.email}
      </p>
    </div>
  );
}

export default User;
userasyncを使用すると、パラメータを含む関数を呼び出す新しい関数が作成され登録されます.その後depsにidを追加し、idを変更するたびに再呼び出す.
そしてUsersjsではuserStateを使用してuserIdステータスを管理します.初期値はnullで、リスト内の項目をクリックすると、クリックしたユーザーのidをuserId値に設定できます.

Users.js

import React, { useState } from 'react';
import axios from 'axios';
import useAsync from './useAsync';
import User from './User';

// useAsync 에서는 Promise 의 결과를 바로 data 에 담기 때문에,
// 요청을 한 이후 response 에서 data 추출하여 반환하는 함수를 따로 만들었습니다.
async function getUsers() {
  const response = await axios.get(
    'https://jsonplaceholder.typicode.com/users'
  );
  return response.data;
}

function Users() {
  const [userId, setUserId] = useState(null);
  const [state, refetch] = useAsync(getUsers, [], true);

  const { loading, data: users, error } = state; // state.data 를 users 키워드로 조회

  if (loading) return <div>로딩중..</div>;
  if (error) return <div>에러가 발생했습니다</div>;
  if (!users) return <button onClick={refetch}>불러오기</button>;
  return (
    <>
      <ul>
        {users.map(user => (
          <li
            key={user.id}
            onClick={() => setUserId(user.id)}
            style={{ cursor: 'pointer' }}
          >
            {user.username} ({user.name})
          </li>
        ))}
      </ul>
      <button onClick={refetch}>다시 불러오기</button>
      {userId && <User id={userId} />}
    </>
  );
}

export default Users;

出典:ベロフトとのモダン反応
1つの項目をクリックするたびに、データがロードされます.
注:ベロフォードとのモダン反応
感じ:
  • 今日APIバインド時にCustom Hookを手作りして試してみました.
  • 用途に合わせて機能をもう少しカスタマイズして、よく考えてからやりましょう.