Jiraっぽいアプリをサクッと作ってみた！

# はじめに
みなさんこんにちは！
[株式会社hokan](https://recruit.hkn.jp/)でフロントエンドエンジニアをしている斉藤と申します！！
初投稿でございます。どうぞよろしくお願いします:clap:
今回はReactで[Jiraのスクラムボード機能](https://www.atlassian.com/ja/software/jira/features)の簡易版を作ったので紹介していこうと思います。
早速ですが成果物はこちらです！
~~https://jira-clone-4e8c1.web.app~~

# 使った技術
<ul>
  <li>react-hook-form</li>
  <li>react-beautiful-dnd</li>
  <li>Firebase</li>
  <li>chakra-ui</li>
</ul>



# react-hook-form
[react-hook-form](https://react-hook-form.com/)はreactのhooksのような感じで使えるフォームライブラリで、react-hook-form側がなんでもやってくれるので、パフォーマンスもよくコードの記述量も減り、onChangeなどを発火させる必要もなくstate管理も楽なパーフェクトライブラリです。

今回はこんな感じで使いました。

```typescript
import {useForm} from 'react-hook-form'

const {
    register,
    formState: { errors, isSubmitting },
    handleSubmit,
  } = useForm({
    defaultValues: { ...initialValues },
  });

<form onSubmit={onSubmit("create")}>
  <ModalBody>
    <FormControl id="stageItem" isInvalid={!!errors.title}>
      <FormLabel>タイトル</FormLabel>
      <Input
        id="title"
        {...register("title", {
        required: "タイトルは必須です",
       })}
       autoFocus
       />
      <FormErrorMessage>
        {errors.title && errors.title.message}
      </FormErrorMessage>
      <Spacer h={4} />
      <FormLabel>内容</FormLabel>
      <Textarea id="content" {...register("content")} />
      <Spacer h={4} />
      <FormLabel>ステータス</FormLabel>
      <Select {...register("statusId")}>
        {Object.values(DefaultTaskStatusMap).map((status) => (
        <option key={status.id} value={status.id}>
          {status.title}
        </option>
        ))}
      </Select>
    </FormControl>
  </ModalBody>
</form>
```
　
```register```でコンポーネントをフックに登録したら、フォームフィールドの値のバリデーションと値を検知することができるようになり、```handleSubmit```の引数に```handleSubmit(customOnSubmit)```みたいな感じで渡してあげると```customOnSubmit```の引数にフォームの入力値が入ってきます。
エラーを検知した場合は```formState```にエラーメッセージが入ってくるのでエラーハンドリングもピャピャッとできちゃいます。
簡単にフォームをコントロールできちゃいますね。


# react-beautiful-dnd
[react-beatutiful-dnd](https://github.com/atlassian/react-beautiful-dnd)はドラッグ&ドロップが簡単にできるライブラリです。
```<DragDropContext />```でドラッグ&ドロップしたいエリアをラップしてあげて、
```<Droppable />```でラップしたエリアにドロップできるようになり、
```<Draggable />```でラップしたアイテムがドラッグできるようになります。
こちらのコードのようになるイメージですね！

```typescript
export const Content: React.FC<Props> = () => {
  const [items, setItems] = useState(_items);
  const onDragEnd = (result: DropResult) => {
    if (!result.destination) return;
    const startIndex = result.source.index;
    const endIndex = result.destination.index;
    const newItems = arrayMove(items, startIndex, endIndex);
    setItems(newItems);
  };
  return (
    <DragDropContext onDragEnd={onDragEnd}>
      <Droppable droppableId={"droppable"} direction={"vertical"}>
        {(provided) => (
          <div ref={provided.innerRef} {...provided.droppableProps}>
            {items.map((item, index) => (
              <Draggable
                key={index}
                index={index}
                draggableId={String(item.id)}
              >
                {(provided) => (
                  <p
                    ref={provided.innerRef}
                    {...provided.draggableProps}
                    {...provided.dragHandleProps}
                  >
                    {item.title}
                  </p>
                )}
              </Draggable>
            ))}
            {provided.placeholder}
          </div>
        )}
      </Droppable>
    </DragDropContext>
  );
};
```

# Firebase
firebaseは今回、[firestore](https://firebase.google.com/docs/firestore)と[hosting](https://firebase.google.com/docs/hosting/)と[auth](https://firebase.google.com/docs/auth)を利用しました。
詳細な説明は省きますが個人で軽くアプリを作りたい時などにおすすめです！

**auth**は今回はGoogle認証だけ使用しました！
こちらはとても簡単でfirebaseのコンソールでGoogle認証をONにしていただいた後、このコードで簡単にGoogle認証できちゃいます！

```typescript
const signInWithGoogle = () => {
    const provider = new firebase.auth.GoogleAuthProvider();
    firebase.auth().signInWithPopup(provider);
  };
```

**firestore**はフロントだけでデータのやりとりができサクッとアプリを作りたいときにいいですね！

**hosting**は
1. firebase cli をインストール
2. firebase init hosting
3. firebase deploy --only hosting

の３ステップで完了するのでとても簡単ですね。



# chakra-ui
今回一番感動したのはなんといってもこちら、[chakra-ui](https://chakra-ui.com/)です。
chakra-uiはReact用のコンポーネントライブラリで少ないコードで「いい感じのui」ができちゃう優れものです。

こんな感じでコンポーネントを```<ChakraProvider><ChakraProvider/>```でラップしてあげるとchakra-uiのテーマが使えるようになり、ダークテーマにも対応しています。

```typescript
import Routes from "Routes";
import { ChakraProvider } from "@chakra-ui/react";

function App() {
  return (
    <ChakraProvider>
      <Routes />
    </ChakraProvider>
  );
}

export default App;
```

どれくらい簡単「いい感じのUI」ができるのかサンプルを用意しました！

```typescript
import {
  Modal as ChakraModal,
  ModalBody,
  ModalOverlay,
  ModalContent,
  ModalHeader,
  ModalCloseButton,
  ModalFooter,
  Button,
  HStack,
  FormControl,
  FormLabel,
  Input,
  Spacer,
  Textarea,
  Select,
  useDisclosure,
} from "@chakra-ui/react";

export const Modal: React.FC = () => {
  const { isOpen, onClose } = useDisclosure();
  return (
    <ChakraModal onClose={onClose} isOpen={isOpen} isCentered>
      <ModalOverlay />
      <ModalContent>
        <ModalHeader>{"タスクを作成"}</ModalHeader>
        <ModalCloseButton />
        <ModalBody>
          <FormControl id="stageItem">
            <FormLabel>タイトル</FormLabel>
            <Input />
            <Spacer h={4} />
            <FormLabel>内容</FormLabel>
            <Textarea />
            <Spacer h={4} />
            <FormLabel>ステータス</FormLabel>
            <Select>
              {Object.values(DefaultTaskStatusMap).map((status) => (
                <option key={status.id} value={status.id}>
                  {status.title}
                </option>
              ))}
            </Select>
          </FormControl>
        </ModalBody>
        <ModalFooter>
          <HStack spacing={3}>
            <Button>{"タスクを作成"}</Button>
            <Button onClick={onClose}>キャンセル</Button>
          </HStack>
        </ModalFooter>
      </ModalContent>
    </ChakraModal>
  );
};
```
こちらのサンプルでこんな感じのモーダルができちゃいます！
![スクリーンショット 2021-07-26 2.39.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262862/04d8e4ea-fea5-73d6-bf90-9cfff7f05b26.png)


このモーダル、chakra-uiのコンポーネントだけで作っているのですがほとんどカスタムしてません。
```const { isOpen, onClose, onOpen } = useDisclosure()```でモーダルやダイアログ、ドロワーなどの状態を管理できたりします。
自分で作るとちょっと面倒なUIも作ってくれており、デフォルトでこんないい感じのUI作れちゃうのはとても気持ちがいいですね。
他にもaria属性の定義や、キーボードナビゲーションへの配慮もあるのでアクセシビリティも問題ありません。
chakra-uiは今後も積極的に使っていきたいと強く思いました！

# 所感
今回はやってみた系の記事でベテランエンジニアの方には特に学ぶこともなかったかと思いますが、駆け出しエンジニアの皆様やフロントやったことないエンジニアの方には役に立っていただけたら嬉しいです！
初めての記事でとても大変でしたがこれからも頑張って描いていこうと思いました。