フリーランス 技術調査ブログ

フリーランス/エンジニア Ruby Python Nodejs Vuejs React Dockerなどの調査技術調査の備忘録

React Hooksでaxiosを利用して外部データを取得しデータを持ちまわる

はじめに

  • 前回、テスト用のAPIを実行してReactで表示するサンプルプログラムを作成しました
  • APIで取得したデータをローカルストレージで持ち待って、reactprouter-domでページ遷移したまま、APIで取得したデータを表示しつづけるプログラムを作成しました。

前回のテストAPIの記事

px-wing.hatenablog.com

サンプルプログラム

Reactのバージョンは16.13.1となりますので、react-hooksが利用できるバージョンでお試しください。

import React, { useState, useEffect } from 'react'
import { Nav, Container, Form, Button, Table } from 'react-bootstrap'
import axios from 'axios'

import Home from './Home'
import UserInfo from './UserInfo'


import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link,
  useRouteMatch,
  useParams
} from 'react-router-dom'

import 'bootstrap/dist/css/bootstrap.min.css';



const App = (props) => {
  const appState = localStorage.getItem('appWithProps')
  const initialState = appState ? JSON.parse(appState) : props
  const [state, setState] = useState(initialState)

  const apiCall = async () => {
    const result = await axios(
      'https://reqres.in/api/users?delay=1',
    ).then((response) => {
      setState({ ...state, data: response.data.data });
    })
  }

  useEffect( () => {
    const fetchData  = async () => {
      const result = await axios(
        'https://reqres.in/api/users?delay=1',
      ).then((response) => {
        setState({ ...state, data: response.data.data });
      })
    }
    fetchData()
  }, [])

  useEffect(() => {
    localStorage.setItem('appWithProps', JSON.stringify(state))
  }, [state])

  const emailInputChange = (e) => setState({ ...state, email: e.target.value })



  return (
    <Router>
      <Container fluid>
        <Nav>
          <Nav.Item>
            <Nav.Link href="/">Home</Nav.Link>
          </Nav.Item>
          <Nav.Item>
            <Nav.Link href="/about">About</Nav.Link>
          </Nav.Item>
          <Nav.Item>
            <Nav.Link href="/topics">Topics</Nav.Link>
          </Nav.Item>
        </Nav>
        <Table striped bordered hover>
          <thead>
            <tr>  
              <th>#</th>
              <th>First Name</th>
              <th>Last Name</th>
              <th>email</th>
              <th>Avatar</th>
            </tr>
          </thead>
          <tbody>
            {
              state.data.map((d,index) => {
                return (
                    <UserInfo key={index} id={d.id} first_name={d.first_name} last_name={d.last_name} email={d.email} avatar={d.avatar} />
                  );
              })
            }
          </tbody>
        </Table>
        <Form>
          <Form.Group controlId="formBasicEmail">
            <Form.Label>Email address</Form.Label>
            <Form.Control type="email" placeholder="Enter email" value={state.email} onChange={emailInputChange} />
          </Form.Group>
          <Button variant="primary" type="button" onClick={apiCall}>検索</Button>
        </Form>
        <Switch>
          <Route path="/about">
            <About email={state.email} />
          </Route>
          <Route path="/topics">
            <Topics email={state.email} />
          </Route>
          <Route path="/">
            <Home email={state.email} />
          </Route>
        </Switch>
      </Container>
    </Router >
  );
}

const Home = (props) => {
  return (
    <>
      <h2>Home</h2>
      <hr />
      <h4>MailAddress: {props.email}</h4>
    </>
  )
}

const About = (props) => {
  return (
    <>
      <h2>About</h2>
      <hr />
      <h4>MailAddress: {props.email}</h4>
    </>
  )
}

const Topics = (props) => {
  let match = useRouteMatch();

  return (
    <div>
      <h2>Topics</h2>
      <hr />
      <h4>MailAddress: {props.email}</h4>
      <ul>
        <li>
          <Link to={`${match.url}/components`}>Components</Link>
        </li>
        <li>
          <Link to={`${match.url}/props-v-state`}>
            Props v. State
          </Link>
        </li>
      </ul>

      <Switch>
        <Route path={`${match.path}/:topicId`}>
          <Topic />
        </Route>
        <Route path={match.path}>
          <h3>Please select a topic.</h3>
        </Route>
      </Switch>
    </div>
  );
}

const Topic = () => {
  let { topicId } = useParams();
  return <h3>Requested topic ID: {topicId}</h3>;
}

App.defaultProps = {
  name: '',
  email: '',
  data: []
}

export default App;

実施に作成した画面

f:id:PX-WING:20200523232459p:plain
サンプル画面