TK-NOTE

技術的なことや趣味、読んだ本についての感想などを投稿してきます。

【react-tabs】簡単にタブ実装を行うReactプラグイン

Cover Image for 【react-tabs】簡単にタブ実装を行うReactプラグイン
React

react-tabsとは?

簡単にタブ実装を行うためのnpmパッケージです。
リポジトリはこちらです

react-tabsでタブ実装してみた

実装してみました。
実装内容としてはマイページによくある「プロフィール情報」、「メールアドレス」、「パスワード」、「アイコン画像」の4タブからなるアカウント情報更新画面のようなものです。タブを切り替えても値が保持されるようにしました。
実装した感想としては本当に使いやすく、必要な時はすぐに導入したいなと感じました。

src/App.js

import "./App.css";
import EmailContextProvider from "./EmailContextProvider";
import IconContextProvider from "./IconContextProvider";
import PasswordContextProvider from "./PasswordContextProvider";
import ProfileContextProvider from "./ProfileContextProvider";
import SampleTab from "./SampleTab";

function App() {
  return (
    <div className="App">
      <ProfileContextProvider>
        <EmailContextProvider>
          <PasswordContextProvider>
            <IconContextProvider>
              <SampleTab />
            </IconContextProvider>
          </PasswordContextProvider>
        </EmailContextProvider>
      </ProfileContextProvider>
    </div>
  );
}

export default App;


src/ProfileContextProvider.js

import React, { createContext, useState } from "react";

export const ProfileContext = createContext();

function ProfileContextProvider({ children }) {
  const [userName, setUserName] = useState("");
  const [nickName, setNickName] = useState("");
  const [message, setMessage] = useState("");
  const [notifyEmail, setNotifyEmail] = useState(false);

  return (
    <ProfileContext.Provider
      value={{
        userName,
        setUserName,
        nickName,
        setNickName,
        message,
        setMessage,
        notifyEmail,
        setNotifyEmail,
      }}
    >
      {children}
    </ProfileContext.Provider>
  );
}

export default ProfileContextProvider;


src/EmailContextProvider.js

import React, { createContext, useState } from "react";

export const EmailContext = createContext();

function EmailContextProvider({ children }) {
  const [email, setEmail] = useState("");

  return (
    <EmailContext.Provider
      value={{
        email,
        setEmail,
      }}
    >
      {children}
    </EmailContext.Provider>
  );
}

export default EmailContextProvider;


src/PasswordContextProvider.js

import React, { createContext, useState } from "react";

export const PasswordContext = createContext();

function PasswordContextProvider({ children }) {
  const [password, setPassword] = useState("");

  return (
    <PasswordContext.Provider
      value={{
        password,
        setPassword,
      }}
    >
      {children}
    </PasswordContext.Provider>
  );
}

export default PasswordContextProvider;


src/IconContextProvider.js

import React, { createContext, useState } from "react";

export const IconContext = createContext();

function IconContextProvider({ children }) {
  const [icon, setIcon] = useState(null);
  const [iconImage, setIconImage] = useState("");
  const onChangeIcon = (e) => {
    const files = e.target.files;
    if (files && files[0]) {
      setIcon(files[0]);
      setIconImage(window.URL.createObjectURL(files[0]));
    }
  };

  return (
    <IconContext.Provider
      value={{
        onChangeIcon,
        iconImage,
      }}
    >
      {children}
    </IconContext.Provider>
  );
}

export default IconContextProvider;


src/SampleTabs.js

import React, { useState } from "react";
import { Tab, Tabs, TabList, TabPanel } from "react-tabs";
import "react-tabs/style/react-tabs.css";
import ProfileForm from "./ProfileForm";
import EmailForm from "./EmailForm";
import PasswordForm from "./PasswordForm";
import { IconContext } from "./IconContextProvider";
import IconForm from "./IconForm";

function SampleTab() {
  return (
    <Tabs defaultIndex={0}>
      <TabList>
        <Tab>プロフィール情報</Tab>
        <Tab>メールアドレス</Tab>
        <Tab>パスワード</Tab>
        <Tab>アイコン画像</Tab>
      </TabList>

      <TabPanel>
        <ProfileForm />
      </TabPanel>

      <TabPanel>
        <EmailForm />
      </TabPanel>
      
      <TabPanel>
        <PasswordForm />
      </TabPanel>

      <TabPanel>
        <IconForm />
      </TabPanel>
    </Tabs>
  );
}

export default SampleTab;


src/ProfileForm.js

import React, { useContext } from "react";
import { ProfileContext } from "./ProfileContextProvider";

function ProfileForm() {
  const handleSubmit = (e) => {
    e.preventDefault();
    // do somthing... such as api call etc
  };
  const {
    userName,
    setUserName,
    nickName,
    setNickName,
    message,
    setMessage,
    notifyEmail,
    setNotifyEmail,
  } = useContext(ProfileContext);

  return (
    <fonm
      style={{
        display: "flex",
        "flex-direction": "column",
        padding: "0 50px 0 50px",
      }}
      onSubmit={(e) => handleSubmit(e)}
    >
      <div>
        <label htmlFor="userName">ユーザー名</label>
        <input
          id="userName"
          type="text"
          value={userName}
          onChange={(e) => setUserName(e.target.value)}
        />
      </div>
      <div>
        <label htmlFor="nickName">ニックネーム</label>
        <input
          id="nickName"
          type="text"
          value={nickName}
          onChange={(e) => setNickName(e.target.value)}
        />
      </div>
      <div>
        <label htmlFor="message">メッセージ</label>
        <input
          id="message"
          type="textarea"
          value={message}
          onChange={(e) => setMessage(e.target.value)}
        />
      </div>
      <div>
        <label htmlFor="notifyEmail">お知らせメールを受け取るか</label>
        <input
          id="notifyEmail"
          type="checkbox"
          checked={notifyEmail}
          onChange={() => setNotifyEmail(!notifyEmail)}
        />
      </div>
      <input
        type="submit"
        style={{ margin: "10px 300px 0 300px" }}
        value="更新する"
      />
    </fonm>
  );
}

export default ProfileForm;


src/EmailForm.js

import React, { useContext } from "react";
import { EmailContext } from "./EmailContextProvider";

function EmailForm() {
  const handleSubmit = (e) => {
    e.preventDefault();
    // do somthing... such as api call etc
  };
  const { email, setEmail } = useContext(EmailContext);

  return (
    <fonm
      style={{
        display: "flex",
        "flex-direction": "column",
        padding: "0 50px 0 50px",
      }}
      onSubmit={(e) => handleSubmit(e)}
    >
      <div>
        <label htmlFor="email">Eメール</label>
        <input
          id="email"
          type="text"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
        />
      </div>
      <input
        type="submit"
        style={{ margin: "10px 300px 0 300px" }}
        value="更新する"
      />
    </fonm>
  );
}

export default EmailForm;


src/PasswordForm.js

import React, { useContext } from "react";
import { PasswordContext } from "./PasswordContextProvider";

function PasswordForm() {
  const handleSubmit = (e) => {
    e.preventDefault();
    // do somthing... such as api call etc
  };
  const { password, setPassword } = useContext(PasswordContext);

  return (
    <fonm
      style={{
        display: "flex",
        "flex-direction": "column",
        padding: "0 50px 0 50px",
      }}
      onSubmit={(e) => handleSubmit(e)}
    >
      <div>
        <label htmlFor="password">パスワード</label>
        <input
          id="password"
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
        />
      </div>
      <input
        type="submit"
        style={{ margin: "10px 300px 0 300px" }}
        value="更新する"
      />
    </fonm>
  );
}

export default PasswordForm;


src/IconForm.js

import React, { useContext } from "react";
import { IconContext } from "./IconContextProvider";

function IconForm() {
  const handleSubmit = (e) => {
    e.preventDefault();
    // do somthing... such as api call etc
  };
  const { onChangeIcon, iconImage } = useContext(IconContext);

  return (
    <fonm
      style={{
        display: "flex",
        "flex-direction": "column",
        padding: "0 50px 0 50px",
      }}
      onSubmit={(e) => handleSubmit(e)}
    >
      <div>
        <label htmlFor="icon">アイコン画像</label>
        <input id="icon" type="file" onChange={(e) => onChangeIcon(e)} />
        <div>
          <img src={iconImage} width="400px" height="400px" />
        </div>
      </div>
      <input
        type="submit"
        style={{ margin: "10px 300px 0 300px" }}
        value="更新する"
      />
    </fonm>
  );
}

export default IconForm;