せきやんのブログ

技術や趣味などについて書きたいことが思いついたら書いていきます。

就活振り返り

はじめに

僕は現地点で23卒のB3なのですが、ありがたいことに第一志望である企業から内定をいただいたので、すでに就活を終了しています。

年が明ける前にこれまでの就活の経験をまとめておきたいと思います。
ぜひこれから就活をする人や、24卒以降の方に参考にしてもらえたら嬉しいです!
ただし、僕はWeb系の企業でエンジニアとして就活をしたので、業種や業界が違う人には参考にならない部分もあるかもしれません。

なお、公開してはまずい情報などもあると思いますので、今回は具体的な企業名や選考内容については触れませんのでご了承ください。
就活中にやったことや考え方、当時の気持ちあたりを伝えれたらと思います!

インターン前までの経歴

大学入学前

ここは一番参考にならないところだと思いますが、僕は

高校卒業 → 専門学校 → 就職 → 退職 → 大学

という経歴があります。

正直初めはこれで就活が不利になると思っていたので、他の部分で力をつけて年齢をカバーすることを意識していました。 ちなみに、IT系とは全く関係ない仕事をしていたので、大学に入るまではプログラミングがなんなのかすらよくわかっていませんでした。

いずれ昔の話もブログに書きたいなーとは思いますが、今回はこれぐらいで。

大学での活動

就活の中で話したことで話した大学での活動はこんな感じです。

課外活動

  • 学生ベンチャー企業「CirKit」で1年時から活動(詳しい活動内容はこちら
    • 1年時にはHP制作を企画立ち上げからやり、初のリーダーとなる
    • 2年時には受託開発の案件のエンジニア兼プロダクトリーダーとして開発に携わる
    • 3年時にはエンジニア以外も含めたCirKitの全学生をまとめるリーダーとして活動
  • 地域活性化として観光地をアプリで盛り上げるプロジェクトにほぼ立ち上げから関わり、iOSアプリ開発やWebサイト製作を行う

個人開発

  • Effector Geek」という音楽機材まとめサイトみたいなものを React で開発
  • 電卓など簡単なアプリを React や Vue で開発

言語経験

  • HTML & CSS: 大体のことはできる
  • JS & TS: 個人制作を中心によく使っていた
  • Ruby: 受託開発で使っていて、だいたいわかってるぐらい
  • Swift: スマホアプリがわからなさすぎて途中で挫折
  • Python: 授業でやった程度だが競プロ系の問題で使っていた
  • C: 授業でやったけどよくわからん
  • Java: 授業でやったけどよくわからん

B3の活動履歴

4月

インターンの応募しなきゃなーと思ってただけ。応募はしてない。
CirKitの活動がまだ忙しくてそれでいっぱいいっぱいでした。

5月 ~ 7月

サマーインターンに本格的に応募を初めて、授業と課外活動とインターン選考で大忙しでしたね。 インターンはWeb系の有名な企業ばかりに合計12社応募して、2社だけなんとか受かりました。 それ以外だと、落ちたけど本選考の書類選考とか一次面接を免除しますみたいに言ってもらえた企業さんがあったのは嬉しかったです。

8月 ~ 9月

前半は課外活動、後半はインターンみたいな感じ。

10月

インターンが終わってホッとする間もなく、インターン選考を受けた企業さんから早期選考の案内が届きました。 5社ぐらいにエントリーして、10月後半から本選考のコーディング試験や面接が始まりました。 まだ課外活動もがっつりあった中で自己分析とかもしないとみたいな感じで結構しんどかったかも。

11月

前半までは、とにかくエントリーした企業の選考を進めてました。

そして中頃に初めてお祈りされた企業が出てきて、ここでメンタルが一気にボロボロに…。 手持ちが減っていくのに、次の企業に申し込むのが億劫みたいな状態がが続いていました。

後半になると就活エージェントから声がかかり、エージェントと面談をしていくつか企業を紹介してもえました。 この面談とかで自分の就活の軸や方向性を整理でき、少し立ち直りはじめることができたため、エージェント経由で3社エントリーしました。 ちなみに使った就活サポートはこの二つです。

12月

自己分析をやり続けたことで、やりたいことがかなり明確になってきている状況でした。 おかげでむしろ就活をいい経験にしたいとか思えるようになってきておりメンタルも回復気味。 この時点で早期選考を受けていた企業がまだ残っていたので、新しくエントリーした会社と合わせて選考を進めていました。

そうしたら中頃になったぐらいで、なんと一番行きたいと思っていた企業さんから内定をいただきました! 承諾してそこで就活は終了です。

就活中にやったこと

企業の探し方

基本的に企業に出会った方法は以下の二つです。

僕のようにインターンから本選考の案内が来るっていうのは結構多いと思うので、インターンの時点から幅広く探せるといいと思います。

企業研究

基本的には、ホームページやその会社のブログ記事などを片っ端から見て、どういう会社なのかを調べましました。

僕がやったことで、おすすめなのは以下3つですね。

  • 企業のまとめメモやノートを作っていつでも見返したり、比較できるようにする
  • 「企業名 決算書」で検索してその企業の決算資料などから企業の方向性や状況を知る
  • 興味を持った企業の説明会やイベントにはできる限り参加する

自己分析

これに関してはこれをやったというのがないんですよね…。 ひたすら「自分がしたいことは何か?」「今後何をやれたら幸せなのか?」とかを自問自答しまくりました。

一つおすすめをするなら、これらをメモに適当に書いた方がいいですね。頭だけで考えるより整理できると思います。 あとは、可能であれば周りの友達や先輩、教授など相談できる人がいれば話を聞いてもらうだけでもいいので話すことがおすすめです。

選考対策

コーディング試験

普段競技プログラミングとかをやっている人であれば、わざわざ対策をする必要はないと思います。

僕は4月ごろまではほとんどやったことがなかったので、AtCoderに登録して過去問を何問か解いてみるぐらいはやりました。

独特なところもあり、慣れがある程度あると思うので、僕と同じようにコンテストに出なくても過去問を解いてみるぐらいはしてみるといいと思います。

面接

どこの面接でも必ず聞かれることがあるので、そこは準備をしました。

  • 1分ぐらいの自己紹介
  • 自分が今までやってきた開発
  • 就活の軸
  • 逆質問

これらはだいたいどの面接でも話すことになると思うので、事前に考えておくといいです。 ただし、一言一句暗記するのではなく、箇条書きとかでポイントをまとめておき、いつでも思い出せるようにしておくのがポイントです。

あと、自分がやってきた開発についてはかなり深堀されるので

  • 開発の経緯
  • 技術選定の理由
  • 自分がどこを担当したのか
  • チームか個人か
  • チームであればどうやってチーム開発を進めたのか
  • 工夫したところ
  • 大変だったこと、それをどうやって乗り越えたか

あたりをまとめておきましょう。

これら以外だと技術系の質問とかもありますが、大抵は小手先のものは通用しないので、うまく答えれたらラッキーぐらいでいいと思います。

就活で大切だと思ったこと

最後に、就活をしていて僕が大切だと思ったことをお伝えしたいと思います。

企業と自分の方向性がマッチするのかが一番大切

選考対策とかいろいろ書きましたが、就活においてはこれが一番大切になります。どれだけ技術力が高くても「この人はうちの企業にはあわないな」と思われてしまったら受からないし、逆にそこまで技術力が高くなくても「この人はうちの企業で頑張れそうだな」と思ってもらえれば採用してもらえます。

これを大切にすれば、就職後のミスマッチとかも減らせると思うので、受ける側もこの企業が自分に合っているかを大切にしてみてください。

僕も最初はあまり興味がないところでも受けてみることをしてましたが、面接時に明らかにお互いがミスマッチだと感じる雰囲気があって不採用になってしまったことがありました。それだとお互いに損しかないので、できる限りマッチした企業を探してみてください。

しんどいのが普通

就活中はしんどいと思うことが多いと思いますが、それは誰もがそうです。優秀だと思うような人でもめちゃくちゃ悩んで就活をしていたりします(たぶん)。

なので、周りを見るのではなく自分がどうなのかを考えればいいですし、メンタルケアも就活の一つです。

友達と遊んだり、好きなことをして休憩をはさみつつ就活をして大丈夫ですよ。

自然体で選考を受けよう

就活はどれだけ話を盛れるかみたいに言う人もいますが、今までやってきたことや考えをしっかり話せればマッチする企業は必ずあります。

なので、自分を普段よりよく見せようとしたり、嘘をついたりすると自分が思っていたところとは違う方向に話が進んでしまい詰むことは珍しくありません。

付け焼き刃の自分ではなく、自然体の自分をどれだけわかりやすく伝えるかというようにしましょう。

まとめ

就活は大変だと思いますが、真剣にやれば終わった後にはいい経験だったと思えるようになります。実際ここまで自分のことを考えることってないと思うので、就活を乗り切ってみんなが成長できることを僕も願っています!

もしもっと細かい話が聞きたいなどあれば、Twitterとかで連絡してもらえれば答えられると思うので、いつでも連絡してください!!

せきやん (@sekiyan372) | Twitter

EmailJSの体験が最高だった

はじめに

静的サイトを制作していて以下のように思ったことはありませんか?

  • 他にバックエンドを実装する気がないけど、お問い合わせは用意したい
  • でもGoogle Formを埋め込むのはなんかかっこ悪い
  • でも簡単に実装したい

僕もまさにそうでした。

そんな時に見つけたのが EmailJS というサービスです。

www.emailjs.com

なんとクライアントサイドだけで Email を送ることができるのです!
しかも JS で書けるし、React のライブラリも用意されている!!

もうこれは使うしかないでしょ!!ということで使ってみました。

開発環境

今回は TS + Next.js + Tailwind CSS で作ることにしました。実行環境は以下の通りです。

  • Node.js v15.14.0
  • yarn 1.22.10
  • typescript@3.9.3
  • next 12.0.3
  • tailwindcss ^2.2.19

実装

1. EmailJSのセットアップ

EmailJS からまずはサインアップしましょう。

f:id:sekiyan372:20211129153602p:plain
EmailJSのサイトのトップ画面

Service の設定

アカウントを作成して、ログインできたら次にどのメールサービスを使うかを登録しましょう。 「Add New Service」をクリックします。

f:id:sekiyan372:20211129154043p:plain
メールサービスの画面

使用するメールサービスを選択しましょう。今回はGmailを使用します。

f:id:sekiyan372:20211129155052p:plain
メールサービスの選択

Name と Service ID を設定しましょう。それぞれ自分が管理しやすいものを設定すれば良いです。
入力ができたら「Create Service」をクリックしましょう。サービスの認証画面にいくと思いますので、流れに沿って進めましょう。

f:id:sekiyan372:20211129155121p:plain
各値の設定

Template の設定

次にメールのテンプレートを用意しましょう。

左のメニューから 「Email Templates」を選択してください。
すでにデフォルトのテンプレートがあるので、それを編集しましょう。

f:id:sekiyan372:20211129160202p:plain
テンプレート選択画面

テンプレートは以下のようになっていると思いますので、好きなように編集しましょう!
編集をしたら「Save」ボタンで忘れずに保存をしましょう。

f:id:sekiyan372:20211129161027p:plain
テンプレート編集画面

2. 導入準備

ライブラリのインストール

以下のコマンドでライブラリを入れましょう。

$ yarn add emailjs-com

環境変数の導入

Next.jsであれば .env.local をルートディレクトリの直下作成し、3つの環境変数を設定します。
クライアント側で使用するので、先頭に NEXT_PUBLIC_をつけましょう。

Service IDは「Email Services」にて、User IDは「ntegration」にて、Template IDは「Email Templates」にて確認できます!

NEXT_PUBLIC_USER_ID=ユーザーのID
NEXT_PUBLIC_SERVICE_ID=サービスのID
NEXT_PUBLIC_TEMPLATE_ID=テンプレートのID

3. コンポーネントへ実装

フォームの作成

まずは基本的なフォームを作成しましょう。

import { ChangeEvent } from "react"
import type { NextPage } from 'next'

const Index: NextPage = () => {
  const onSubmit = (event: ChangeEvent<HTMLFormElement>) => {
    event.preventDefault()
    console.log(event)
  }

  return(
    <div className="m-8 flex justify-center items-center flex-col">
      <div className="text-5xl">Contact</div>

      <div className="md:m-10 md:w-3/4 w-11/12 ">
        <form onSubmit={onSubmit}>
          <div className="m-5">
            <label htmlFor="name" className="block">name</label>
            <input
              type="text"
              id="name"
              className="border-solid border border-black rounded w-full p-2"
            />
          </div>

          <div className="m-5">
            <label htmlFor="email" className="block">email</label>
            <input
              type="text"
              id="email"
              className="border-solid border border-black rounded w-full p-2"
            />
          </div>

          <div className="m-5">
            <label htmlFor="message" className="block">message</label>
            <textarea
              id="message"
              className="border-solid border border-black rounded w-full p-2"
              rows={5}
            />
          </div>

          <div className="text-center">
            <button
              className="border-solid border rounded p-2 bg-green-500 text-white text-xl hover:opacity-70"
            >
              送信
            </button>
          </div>
        </form>
      </div>
    </div>
  )
}

export default Index

以下のようになります!

f:id:sekiyan372:20211129171238p:plain
フォームの作成

フォームの値の State 設定する

次に、useState を使ってフォームの値を管理する State を設定します。

const [name, setName] = useState<string>('')
const [email, setEmail] = useState<string>('')
const [message, setMessage] = useState<string>('')

フォームの value に State を、onChange に setState を組み込んで、フォームの値が変わった時に State を更新するようにしましょう。

<input
  //省略
  value={name}
  onChange={(e) => setName(e.target.value)}
/>

メール送信実装

まず設定した環境変数を読み込む必要があります。
僕はこの環境変数の読み込みとその初期化を行う処理を設定ファイルを utils ディレクトリの配下に作成しました。

import { init } from 'emailjs-com'

const config = {
  userId: process.env.NEXT_PUBLIC_USER_ID,
  serviceId: process.env.NEXT_PUBLIC_SERVICE_ID,
  templateId: process.env.NEXT_PUBLIC_TEMPLATE_ID
}

if (
  config.userId !== undefined &&
  config.serviceId !== undefined &&
  config.templateId !== undefined
) {
  init(config.userId)
}

export const emailjsConfig = config

そうしたら、実際にフォームの方に送信処理を書いていきます。 まずはメール送信をする send メソッドと先程の設定ファイルをインポートしましょう。

import { send } from 'emailjs-com'
import { emailjsConfig } from '~/utils/Emailjs'

sendMail メソッドを作成し、メール送信の処理を書いていきます。
初めのif文は undefined でのエラーを解消するための処理になっています。
そして、template_param ではメールに送信される値を設定されています。この値がそのまま EmailJS のメール側に反映されるので注意しましょう。
そして、send メソッドに値を渡して送信します。この時、Stateの値をリセットするようにしています。

const sendMail = () => {
  if (
    emailjsConfig.serviceId !== undefined &&
    emailjsConfig.templateId !== undefined
  ) {
    const template_param = {
      to_name: name,
      from_email: email,
      message: message,
    }

    send(
      emailjsConfig.serviceId,
      emailjsConfig.templateId,
      template_param
    ).then(() => {
      window.alert('お問い合わせを送信致しました。')
      setName('')
      setEmail('')
      setMessage('')
    })
  }
}

上記で作成した sendMail メソッドを onSubmit の中に追加しましょう。

const onSubmit = (event: ChangeEvent<HTMLFormElement>) => {
  event.preventDefault()
  sendMail()
}

これで、送信はできるはずなので、実際にフォームに入力をしてテスト送信をしてみましょう!

実装まとめ

最後に今までのコードをまとめたものを載せておきます。

import { init } from 'emailjs-com'

const config = {
  userId: process.env.NEXT_PUBLIC_USER_ID,
  serviceId: process.env.NEXT_PUBLIC_SERVICE_ID,
  templateId: process.env.NEXT_PUBLIC_TEMPLATE_ID
}

if (
  config.userId !== undefined &&
  config.serviceId !== undefined &&
  config.templateId !== undefined
) {
  init(config.userId)
}

export const emailjsConfig = config

import { ChangeEvent, useState } from "react"
import type { NextPage } from 'next'
import { emailjsConfig } from '~/utils/Emailjs'
import { send } from 'emailjs-com'

const Index: NextPage = () => {
  const [name, setName] = useState<string>('')
  const [email, setEmail] = useState<string>('')
  const [message, setMessage] = useState<string>('')

  const sendMail = () => {
    if (
      emailjsConfig.serviceId !== undefined &&
      emailjsConfig.templateId !== undefined
    ) {
      const template_param = {
        to_name: name,
        from_email: email,
        message: message,
      }

      send(
        emailjsConfig.serviceId,
        emailjsConfig.templateId,
        template_param
      ).then(() => {
        window.alert('お問い合わせを送信致しました。')
        setName('')
        setEmail('')
        setMessage('')
      })
    }
  }

  const onSubmit = (event: ChangeEvent<HTMLFormElement>) => {
    event.preventDefault()
    sendMail()
  }

  return(
    <div className="m-8 flex justify-center items-center flex-col">
      <div className="text-5xl">Contact</div>

      <div className="md:m-10 md:w-3/4 w-11/12 ">
        <form onSubmit={onSubmit}>
          <div className="m-5">
            <label htmlFor="name" className="block">name</label>
            <input
              type="text"
              id="name"
              className="border-solid border border-black rounded w-full p-2"
              value={name}
              onChange={(e) => setName(e.target.value)}
            />
          </div>

          <div className="m-5">
            <label htmlFor="email" className="block">email</label>
            <input
              type="text"
              id="email"
              className="border-solid border border-black rounded w-full p-2"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
            />
          </div>

          <div className="m-5">
            <label htmlFor="message" className="block">message</label>
            <textarea
              id="message"
              className="border-solid border border-black rounded w-full p-2"
              rows={5}
              value={message}
              onChange={(e) => setMessage(e.target.value)}
            />
          </div>

          <div className="text-center">
            <button
              className="border-solid border rounded p-2 bg-green-500 text-white text-xl hover:opacity-70"
            >
              送信
            </button>
          </div>
        </form>
      </div>
    </div>
  )
}

export default Index

まとめ

こんなに簡単にお問い合わせの実装がクライアント側のコードを少し書いただけでできるというのは本当にすごいので、ぜひ使ってみて欲しいです! 面倒なメール周りの処理を自分でやらなくていいので、爆速でメールフォームを実装しちゃいましょう!!

参考記事

zenn.dev

React と Tailwind CSS で縦方向のカルーセル(スライダー)を実装したい

はじめに

久しぶりのブログ更新です。

このサイトを見ていたら「ページ全体で縦方向にスライドするページって良くね…?」って思い実装意欲が湧いたので、実際に作ってみました。 僕と同じで縦方向にスライドするページの良さに目覚めたら参考にしてください。

技術選定

実行環境

今回は TS + React + Tailwind CSS で作ることにしました。実行環境は以下の通りです。

  • Node.js v15.14.0
  • yarn 1.22.10
  • typescript@3.9.3
  • tailwindcss ^2.2.19

どうやるか?

React でスライドを実装するライブラリはそこそこあって、どれも悪くはないのですがなんでそう動いているのかわかりにくいというのがなんとなく嫌でした。

ics.media

というわけで、勉強もかねて今回はなるべくJSやCSSを駆使して自分で実装をしていく方向性でいきます。

縦方向のスライドで重要なのが、画面スクロールに対してページ移動をコントロールすることです。 そこで目をつけたのが Intersection Observer です。

Intersection Observerとは?

MDNの説明は以下の通りです。

Intersection Observer API (交差監視 API) は、ターゲットとなる要素が、祖先要素もしくは文書の最上位のビューポートと交差する変更を非同期的に監視する方法を提供します。

developer.mozilla.org

要は、画面外でスクロールしてはみ出した部分と交差したところを監視して、それに合わせて動作を起こせるというAPIみたいです。 Scroll イベントでの発火で操作するよりパフォーマンスもいいらしいので、なんかいい感じですね!

react-intersection-observerを使う

良さげな Intersection Observer API をそのまま使っても良かったのですが、React には react-intersection-observer という便利なライブラリがあるみたいで、すごい使いやすそうなので使っていきます!

yarn コマンドで入れていきましょう。

$ yarn add react-intersection-observer

実装

Reactの細かい環境や設定はそれぞれ好きなようにしましょう。

1. スクロールが止まる部分の実装

まずは画面をスクロールしたらピタッと止まるようにします。
そのためには、CSSscroll-snap-type を設定します。1つ目の値にスナップさせるスクロール方向、2つ目の値に厳密さを指定します。
大きさは横幅100%、縦幅100vhを指定して、今回は縦スクロールなので overflow-y: auto を指定しています。 これらをCSSで記述するとこのようになります。

親要素 {
  width: 100%;
  height: 100vh;
  scroll-snap-type: y mandatory;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

そして、小要素に scroll-snap-align: start を追加することで、スクロールが止まる位置を決定します。

子要素 {
  width: 100%;
  height: 100vh;
  scroll-snap-align: start;
}

これらを Tailwind CSS で記述すると以下のようになります。
Tailwind には scroll-snap-typescroll-snap-align で欲しい値がないので、自分でutilities に設定しましょう。

import { FC } from 'react'

const Index: FC = () => {
  return (
    <div className="w-full h-screen snap overflow-y-auto scrolling-touch">
      <section
        id="section1"
        className="w-full h-screen snap-start flex justify-center items-center bg-red-500 text-5xl text-white"
      >
        Section1
      </section>
      <section
        id="section2"
        className="w-full h-screen snap-start flex justify-center items-center bg-yellow-500 text-5xl text-white"
      >
        Section2
      </section>
      <section
        id="section3"
        className="w-full h-screen snap-start flex justify-center items-center bg-green-500 text-5xl text-white"
      >
        Section3
      </section>
    </div>
  )
}

export default Index
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer utilities {
  .snap {
    scroll-snap-type: y mandatory;
  }
  .snap-start {
    scroll-snap-align: start;
  }
}

以下のようになります!

f:id:sekiyan372:20211128205559g:plain
Sectionごとにピタッと止まる

2. ページネーションの実装

右側に表示するページネーションを実装します。
特別なことはないので、ここの説明は省略します。

以下を追加しましょう。

//親要素のdivタグの中に追加
<nav id="pagination" className="fixed top-1/2 right-8 nav-transform">
  <a
    className="block w-3 h-3 my-6 rounded-full bg-white pagination-transition"
    href="#section1"
  />
  <a
    className="block w-3 h-3 my-6 rounded-full bg-white pagination-transition"
    href="#section2"
  />
  <a
    className="block w-3 h-3 my-6 rounded-full bg-white pagination-transition"
    href="#section3"
  />
</nav>
/* utilitiesに追加 */
.nav-transform {
  transform: translateY(-50%);
}
.pagination-transition {
  transition: transform 0.2s;
}

以下のようになります!

f:id:sekiyan372:20211128211518g:plain
ナビゲーションでの移動

3. 現在表示中のスライドの取得

ページネーションですが今いるスライドの点を大きくしたりして、わかりやすくしたいですよね!
そのためには現在どのスライドが表示されているのかという情報を管理する必要があります。
そこでついに先ほど紹介した react-intersection-observer の出番です!

react-intersection-observer では、以下のようなHooksが用意されており、Intersection Observer API の機能を使うことができます。これがとても使いやすい!!

const [ref, inView] = useInView({
    //パラメータをここに書く
});

ref には監視するDOMの情報が入り、inView には監視している部分が表示されていれば true が、表示されていなければ false が入ります。 この値をそれぞれ組み込んでいきましょう。

inView によってclassNameの値を変更したいので、classNamesというライブラリを使います。

$ yarn add classnames

以下のようにHooksの追加と、 section と a タグに値を追加・変更していきましょう。

//classnamesをインポート
import ClassNames from "classnames"

//Hooksの設定(sectionの数だけ作る)
const [ref1, inView1] = useInView({
  rootMargin: '-50% 0px',
  threshold: 0,
})

//sectionタグにrefを追加
ref={ref1}

//aタグのclassNameを変更
className={ClassNames(
  'block w-3 h-3 my-6 rounded-full bg-pagination-white pagination-transition',
  inView1 ? 'pagination-active' : ''
)}
/* utilitiesに追加 */
.pagination-active {
  transform: scale(1.8);
}

以下のようになります!

f:id:sekiyan372:20211128214933g:plain
表示しているページに合わせてナビゲーションのサイズが変わる

4. スムーススクロールの実装

最後に、ナビゲーションをクリックした時にスクロールがスムーズに動くようにしましょう!

クリックした場所に対応するsectionのidを取得して、scrollIntoView() メソッドを使ってスムーズにスクロールをするようにします。

以下のような関数を作って、a タグをクリックしたときにその関数を呼び出しましょう。

//スムーススクロールをする関数
const smoothScroll = (event: MouseEvent<HTMLElement>) => {
  event.preventDefault()
  const eventTarget = event.target as HTMLAnchorElement
  const eventTargetId = eventTarget.hash
  const scrollTarget = document.querySelector(eventTargetId)
  if (scrollTarget) {
    scrollTarget.scrollIntoView({ behavior: "smooth" })
  }
}

//aタグにonClickを追加
onClick={e => smoothScroll(e)}

以下のようになります!

f:id:sekiyan372:20211128220636g:plain
スムーズにスクロールする

全体のコード

これで完成となるので、今までの実装をしたものを以下に載せておきます!

import { FC, MouseEvent } from "react"
import { useInView } from 'react-intersection-observer'
import ClassNames from "classnames"

const Index: FC = () => {
  const [ref1, inView1] = useInView({
    rootMargin: '-50% 0px',
    threshold: 0,
  })

  const [ref2, inView2] = useInView({
    rootMargin: '-50% 0px',
    threshold: 0,
  })

  const [ref3, inView3] = useInView({
    rootMargin: '-50% 0px',
    threshold: 0,
  })

  const smoothScroll = (event: MouseEvent<HTMLElement>) => {
    event.preventDefault()
    const eventTarget = event.target as HTMLAnchorElement
    const eventTargetId = eventTarget.hash
    const scrollTarget = document.querySelector(eventTargetId)
    if (scrollTarget) {
      scrollTarget.scrollIntoView({ behavior: "smooth" })
    }
  }

  return (
    <div className="w-full h-screen snap overflow-y-auto scrolling-touch">
      <section
        ref={ref1}
        id="section1"
        className="w-full h-screen snap-start flex justify-center items-center bg-red-500 text-5xl text-white"
      >
        Section1
      </section>
      <section
        ref={ref2}
        id="section2"
        className="w-full h-screen snap-start flex justify-center items-center bg-yellow-500 text-5xl text-white"
      >
        Section2
      </section>
      <section
        ref={ref3}
        id="section3"
        className="w-full h-screen snap-start flex justify-center items-center bg-green-500 text-5xl text-white"
      >
        Section3
      </section>

      <nav id="pagination" className="fixed top-1/2 right-8 nav-transform">
        <a
          className={ClassNames(
            'block w-3 h-3 my-6 rounded-full bg-white pagination-transition',
            inView1 ? 'pagination-active' : ''
          )}
          href="#section1"
          onClick={e => smoothScroll(e)}
        />
        <a
          className={ClassNames(
            'block w-3 h-3 my-6 rounded-full bg-white pagination-transition',
            inView2 ? 'pagination-active' : ''
          )}
          href="#section2"
          onClick={e => smoothScroll(e)}
        />
        <a
          className={ClassNames(
            'block w-3 h-3 my-6 rounded-full bg-white pagination-transition',
            inView3 ? 'pagination-active' : ''
          )}
          href="#section3"
          onClick={e => smoothScroll(e)}
        />
      </nav>
    </div>
  )
}

export default Index
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer utilities {
  .snap {
    scroll-snap-type: y mandatory;
  }
  .snap-start {
    scroll-snap-align: start;
  }
  .nav-transform {
    transform: translateY(-50%);
  }
  .pagination-transition {
    transition: transform 0.2s;
  }
  .pagination-active {
    transform: scale(1.8);
  }
}

まとめ

長くなりましたが、これで自分で縦方向のカルーセル(スライダー)を実装することができました! スライドの中身は自由に変更ができるので、好きなように作成をしましょう!

僕はこれで自分のポートフォリオサイトを作ったので、ぜひ参考にしてください!

www.sekiyan372.jp

github.com

参考記事

ics.media

そろそろ CirKit について語りたい

ごあいさつ

みなさま初めまして。せきやんと言います。
初めてのブログ投稿ということで、初めのネタは私が現在リーダーを務めるCirKitという組織について紹介しようと思います。

ちなみに↓の動画で話しているのが自分だったりします。

youtu.be

CirKitとは?

CirKitは金沢工業大学の学生が集って活動する学生団体のような組織ですが、実は正式に株式会社として活動しています。

「学生の進化を創る」という理念で活動しており、学生自身の成長へとつながる活動をしつつ、利益追求も行っています。

具体的に行っているのはシステム開発や動画作成、SAKITOサービスやイベントの運営などです。詳しくはホームページを見てほしいです!!

せきやんのCirKitでの経歴

まずは、僕がCirKitでやってきたことについてざっくり説明します。
ちなみに、CirKitは12月に体制が入れ替わるのでそれに合わせた形になっています。

1期(大学1年の4月〜1年11月まで)

大学に入ってやる気に満ち溢れていた僕は、いろいろプロジェクトを見学しに行って株式会社とし活動しているところとWeb開発が面白そうだったので思って入ることを決めました。あと、見学に行った時に先輩がかなりラフに話してくれてなんか楽しそうだなぁと思ったのも理由の一つだった気がします。

そして、システム部として入ってからは先輩が研修をしてくれてHTML、CSSJavaScriptRubyGithubなどの勉強をしました。

2期(大学1年の12月〜2年11月まで)

第2期では以下のようなことをやりました。

  • システム部の部長
  • @連絡網の開発(途中からチームリーダー)
  • コーポレートサイト制作のチームリーダー

こうやって書くと全部リーダーやってますね…
いろいろと経験を積みたいと思っていたので、とにかく役職に積極的に取り組みました。

システム部の部長は、部署全体の様子を見ながら仕事を割り振ったりする感じですね。 これについてはやることが多いわけではないので大変ではなく、システム部のバランサー的な役割だったと思います。

@連絡網はCirKitで請け負っている開発なのですが、開発経験がなかったので初めはかなり苦労しました。 ただ、いろいろあって5月くらいからリーダーをやることになってからはコードを書くだけでなくて、チームのマネジメントやレビューなどもするようになったので結構がんばりました。

コーポレートサイトは、当時CirKitの会社のHPがなくて、提案して1年の春休みを使って作りました。 この時にReactなど初めて使う技術を導入したり勉強しながらやれたのでよかったですね。

3期(大学3年の4月〜9月現在)

3期になってからは以下のようなことをやっています。

  • 全体のリーダー
  • @連絡網の開発リーダー

3期になると2期での経験を活かしてCirKit全体を統括するリーダーになりました。 リーダーになってからは部署の編成、理念の変更、全員の個人面談、オフィスづくりなど組織のベースを見直し改善を行なってきました。

@連絡網のリーダーは2期から継続です。これについては無事3月ごろにユーザーに使っていただく段階まで来たので、今は運用や改善を行なっています。なんとかリリースまで行けたのはいい経験でした!

CirKitのカルチャー

CirKitには独自のカルチャー(雰囲気?)みたいなものがあります。その中のいくつかをご紹介します!(経験が元なのでシステム寄りかも)

先輩から後輩へ受け継がれる

CirKitに入ると先輩からいろいろなことを教えてもらえます。 システム開発では毎年新人研修が半年かけて行われ、先輩から直接指導を受けることができるため、入った時にはできることが少なくても続けていれば成長できます。また、技術についての情報を教えてもらえたりもします。

先輩から受け継がれるのは技術だけではありません。CirKitのメンバーはインターンなどに参加する人も多く、様々なインターンの情報や就活の体験談なども聞くことができます。

さらにプライベートなことで言えば、大学の教科書や過去問なんかも受け継がれている かも しれません。

メンバーの個性が強い

CirKitでよく言われるのは、メンバーの個性が強いということですね。癖が強いとか、独特な雰囲気を持っている人が多いとも言えるかもしれません。まぁプロジェクトの中でも「株式会社として活動してます!」という団体に入ろうと思う人が集まっていると考えれば、それはそうだろということかもしれません。

中には個性が強すぎてそれぞれがぶつかりあうこともありますが、それはそれでいいことかなと僕は思っています。

LT会

CirKitではLT会というものがたまに行われます。LTとは5分ぐらいの短い時間でテーマに合わせてプレゼンすることです。

技術についてのLTというのもありますが、みんなで楽しめるような趣味のLTなんかもあります。 自分の好きなことを、みんなに知ってもらうチャンスということで僕もLTがある時は気合いを入れて参加をします!

CirKitが抱える問題点

いい面ばかり書いていても胡散臭く見えるかもしれないので、リーダー視点から見た問題点を書こうと思います。

リーダーをやりたがらない

今のCirKitはリーダーなどのまとめる立場をやりたがる人がそんなにいないなと感じています。 僕の経歴を見るとそんなことないと思うかもしれませんが、逆に言えば他にやり手がいなかったから僕がやっていたという側面もあります。

確かにリーダーというのは大変なことも多いかもしれませんが、リーダーだからこそ経験できることもたくさんあるので、もっとみんなには積極的にリーダーや役職についてほしいと思いますね。

コミュニケーションが不足している

CirKitではコロナウイルスの影響もあってここ2年ぐらいはほぼリモートを中心とした活動をしてきました。 リモートでも活動を続けることができたことはよかったのですが、そこで出てきた課題がコミュニケーションが不足していることでした。 やはり直接話すのとテキストやZOOMでのやりとりでは雑談などから生まれる会話などができづらいので、自然に発生するコミュニケーションというのが生まれにくかったです。

現在では、可能な時は対面でミーティングを行ったり、オンラインでもできる方法を模索するなど改善中です。

CirKitが目指してほしい姿

もうすぐ僕もリーダーの任期が終了するので、これからこうあってほしいなという個人的な気持ちを書きたいと思います。

メンバーの成長のためにCirKitを使い倒してほしい

CirKitは学生ひとりひとりが成長できる場になってほしいと僕は思っています。ひとりではできないような規模のことでもメンバーをまきこめばできるようになりますし、多少ならお金がかかるようなことでも正しい使い方であれば会社がカバーしてくれます。

やりたいことができるというよりは、やりたいことをやるためにどう周りに話を通すかということが大切になってくるので、そこまで込みで学ぶことができると思うのがいいと思います。

大切なのはCirKitに入ってから自分からいろいろなことに関わることかなと思います。そういう人が成長できる環境は整っていると思うので、積極的であってほしいなと思います。

進む方向が見つかる場所に

CirKitは今は基本的に技術力とかはなくても、やる気があれば入れるようになっていまし、これからもそうあってほしいです。

むしろ個人的にはまだやりたいことが決まっていない人にCirKitに入ってきてほしいなと思っています。 CirKitに所属するとやることが自然とできてくるので、そういった業務を通して経験を積む中で自分の方向性を見つけることができるという場所であってほしいと思います。

今よりもっと元CirKitメンバーが活躍するのがあらゆるところで見れるようになったら嬉しいですね。

できなかったことができるようになってほしい

CirKitでは技術的な勉強もしますが、実はCirKitはそれ以上に人とのコミュニケーション、チームマネジメント、交渉術のような社会に出て求められるようなことが学べる機会が多いです。時にはメンバー同士でうまくいかない時に、それを改善するために行動するということも必要になってきます。

技術ができない人はそれを学ぶということももちろんやってほしいですし、技術ができる人でもコミュニケーションが苦手であればそれをできるようにする。そんな場であってほしいと僕は思います。

さいごに

今回何が言いたいかというと、CirKitは楽しいです。というかいろいろ書きましたが一番は楽しむことだと思います。

もちろん今まで辛いこともしんどいこともありましたが、僕はCirKitが楽しくて好きだからここまでやって来れました。

宣伝ぽくなってしまったかもしれませんが、この記事を読んで興味を持ってくれる人がいたら嬉しいですね。 何か気になったことがあったらTwitterとかで聞いてください。

twitter.com