0
0
お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

[React] Reactでの非同期処理について考える

Last updated at Posted at 2024-06-15

React での非同期処理

Reactでの非同期処理の歴史

  1. コンポーネントのライフサイクルを使用
  2. Reduxミドルウェアを使用
  3. useEffect Hooks を使用

コンポーネントのライフサイクルを使用

Reactがリリースされた当初は、componentDidMountといったReact のライフサイクルを利用し、非同期処理を実施していました。

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hits: [] };
  }
 
  async componentDidMount() {
    const result = await axios(
      'https://hn.algolia.com/api/v1/search?query=redux',
    );
 
    this.setState({ hits: result.data });
  });
 
  return (
    <ul>
      {data.hits.map(item => (
        <li key={item.objectID}>
          <a href={item.url}>{item.title}</a>
        </li>
      ))}
    </ul>
  );
}

:pencil: デメリット

  • ロジックが追加されるごとに、コンポーネントが肥大化していく

Redux Middleware

その後、Reduxがグローバルな状態管理ライブラリとして普及していくと、データフローの一環として、Reduxに非同期処理も任せるようになっていきました。

ReduxにはMiddlewareといった機能が搭載されており、Reducerの実行前後に任意の処理を追加することができました。

Middleware ライブラリとして Redux ThunkRedux Saga などが利用されていました。

import { Action, Dispatch } from 'redux';
import { ThunkAction } from 'redux-thunk';
import { AppState } from './store';

const initialState = {};

// Reducerの定義
export default function todosReducer(state = initialState, action: Action<string>) {
  switch (action.type) {
    case 'todos/todosLoaded':
      return {
        ...state,
        todos: action.payload
      };
    default:
      return state;
  }
}

// Thunk function
export const fetchTodos = (): ThunkAction<void, AppState, null, Action<string>> => async (dispatch: Dispatch, getState: () => AppState) => {
  try {
    const response = await client.get('/fakeApi/todos');
    dispatch({ type: 'todos/todosLoaded', payload: response.todos });
  } catch (error) {
    console.error('Failed to fetch todos:', error);
  }
}

:pencil: デメリット

  • 学習コストが高い
  • ボイラープレートが多い
  • Storeの構造が過度に複雑化
  • 使用するミドルウェアでコミュニティが分断される

useEffect Hooks

React 16.8 から、非同期処理の課題を解決するためのソリューションが公式によって追加されました。
それが useEffect Hooks です。

useEffect の中で非同期処理を定義することでコンポーネントの肥大化を防ぐことができるようになりました。

import { FC, useEffect, useState } from 'react';

import { requestPath, weatherConditionsMap } from './data';
import { Weather } from './domain/type';

const SampleAsynchronous: FC = () => {
  const [weather, setWeather] = useState<Weather>({} as never);

  useEffect(() => {
    const getTodayWeather = () => {
      fetch(requestPath)
        .then((data) => data.json())
        .then((json) => {
          setWeather((state) => ({
            ...state,
            code: weatherConditionsMap[json.current.weather_code],
            temperature: json.current.temperature_2m,
          }));
        });
    };

    void getTodayWeather();
  }, []);

  return (
    <>
      <h1>Tokyo Weather</h1>
      {weather.code ? (
        <>
          <div>{`現在の東京の天気は${weather.code}です`}</div>
          <div>{`温度: ${weather.temperature}℃`}</div>
        </>
      ) : (
        'data loading...'
      )}
    </>
  );
};

export default SampleAsynchronous;

詳細コード: https://github.com/PenPeen/react_practice/pull/43

まとめ

非同期処理も扱いやすくなっていることがわかりますね...

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