0
0

More than 1 year has passed since last update.

Reactで条件分岐

Posted at

やること

ボタンをクリック → ローディング画面 → 結果

前提

以前作成した下記記事の環境からスタート

必要な材料

① ボタン
app.tsxのreturn内に<button>ボタン</button>を追加する

② ローディング画面
以前、作成した下記記事を参考に作成します。

③ 結果画面
こちらも以前、作成した下記記事を参考に作成します。

ここまでで確認

必要な材料を全て統合した結果
app.tsx

import React, { FC, useEffect, useState } from "react";
import { Reset } from "styled-reset";
import styled, { keyframes } from "styled-components";

import { Content } from "./component/content";
import { Ranking } from "./types/type";

const App: FC = () => {
const [ranking, setRanking] = useState<Ranking[]>([]);

useEffect(() => {
    const fetchData = async () => {
    const response = await fetch("http://localhost:3000/ranking");
    const rankingData = await response.json();
    setRanking(rankingData);
    };
    fetchData();
}, []);
return (
    <>
    <Reset />
    <button>ボタン</button>
    <Load>Loading</Load>
    <Content ranking={ranking} />
    </>
);
};
export default App;

const opacityLoad = keyframes`
0% {
    left: 0;
    opacity: 0;
}
10% {
    left: 10%;
    opacity: 0.5;
}
30% {
    left: 30%;
    opacity: 1;
}
50% {
    left: 50%;
    opacity: 1;
}
70% {
    left: 70%;
    opacity: 0;
}
100% {
    left: 100%;
    opacity: 0;
}
`;
const Load = styled.p`
animation: ${opacityLoad} 2.3s linear infinite;
font-size: 50px;
position: relative;
width: 300px;
`;

content.tsx

import React, { FC } from "react";
import styled from "styled-components";

import { RankingData } from "../types/type";

export const Content: FC<RankingData> = (props) => {
const { ranking } = props;
return (
    <>
    <StyledH1>Hello Hello</StyledH1>
    <table>
        <tr>
        {ranking.map(({ word }) => {
            return (
            <tr>
                <td key={word}>{word}</td>
            </tr>
            );
        })}
        </tr>
    </table>
    </>
);
};

const StyledH1 = styled.h1`
font-size: 50px;
text-align: center;
`;
  1. ターミナルでyarn start
  2. 別のターミナルでyarn mock
  3. ブラウザでlocalhost:8111にアクセス
    画面上にボタン,テスト テスト1 テスト2,Hello Hello,Loadingが表示されていたらOK!

条件分岐

今のままでは、全てが表示されている状態なので、ここから階層とコードを分けていきます。

app.tsx --- main.tsx(条件分岐) --- loading.tsx
                             |
                             --- ranking.tsx(content.tsxからファイル名変更)

app.tsx

import React, { FC, useEffect, useState } from "react";
import { Reset } from "styled-reset";

import { Main } from "./component/main";
import { Ranking } from "./types/type";

const App: FC = () => {
const [ranking, setRanking] = useState<Ranking[]>([]);
const [loading, setLoading] = useState<string>("");

useEffect(() => {
    const fetchData = async () => {
    const response = await fetch("http://localhost:3000/ranking");
    const rankingData = await response.json();
    setRanking(rankingData);
    };
    fetchData();
}, []);
const search = () => {
    setLoading("Loading");
    // 変更を見るため、意図的に遅らせている
    setTimeout(() => setLoading("Ranking"), 5000);
};

return (
    <>
    <Reset />
    <button onClick={() => search()}>ボタン</button>
    <Main loadingData={loading} ranking={ranking} />
    </>
);
};
export default App;

main.tsx

import React, { FC } from "react";
import { Data } from "../types/type";
import { Loading } from "./loading";
import { Ranking } from "./ranking";

export const Main: FC<Data> = (props) => {
const { ranking, loadingData } = props;
return (
    <main>
    {loadingData === "Loading" && <Loading />}
    {loadingData === "Ranking" && <Ranking ranking={ranking} />}
    </main>
);
};

Dataの型であるtypes>type.d.tsに下記を追加

export interface Data {
  ranking: Ranking[];
  loadingData: string;
}

loading.tsx

import React, { FC } from "react";
import styled, { keyframes } from "styled-components";

export const Loading: FC = () => {
return <Load>Loading</Load>;
};

const opacityLoad = keyframes`
0% {
    left: 0;
    opacity: 0;
}
10% {
    left: 10%;
    opacity: 0.5;
}
30% {
    left: 30%;
    opacity: 1;
}
50% {
    left: 50%;
    opacity: 1;
}
70% {
    left: 70%;
    opacity: 0;
}
100% {
    left: 100%;
    opacity: 0;
}
`;
const Load = styled.p`
animation: ${opacityLoad} 2.3s linear infinite;
font-size: 50px;
position: relative;
width: 300px;
`;

※app.tsxにいたものを分解させただけ

ranking.tsx

import React, { FC } from "react";

import { RankingData } from "../types/type";

export const Ranking: FC<RankingData> = (props) => {
  const { ranking } = props;
  return (
    <>
      <table>
        <tr>
          {ranking.map(({ word }) => {
            return (
              <tr>
                <td key={word}>{word}</td>
              </tr>
            );
          })}
        </tr>
      </table>
    </>
  );
};

※こちらもcontent.tsxにいたものをファイル名を変更しただけ(Hello Helloは今回いらないので削除)

確認

  1. ターミナルでyarn start
  2. 別のターミナルでyarn mock
  3. ブラウザでlocalhost:8111にアクセス
    画面上にボタンがあるので、クリックしLoadingが表示、5秒後にテスト テスト1 テスト2されていたらOK!

最後に

簡易的ではありますが、ボタンをクリックしたら結果が出てくるまでの時間にLoadingを表示することができました。
今回はHooksのUseStateを多用してましたが、ここからReduxに置き換えていくとコードもスッキリするので良いと思います。

参考文献

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