20200426のReactに関する記事は8件です。

Nextjsでビルド時ではなく、アプリ起動時に環境変数を読み込ませる方法

概要

Nextjsでビルド時ではなく、アプリ起動時に環境変数を設定する方法を調べたのでメモとして残している。

next.config.jsの設定

以下のように設定する。

// .envファイルから読み込むように設定している。
require("dotenv").config();

module.exports = {
  // ビルド時に利用できる環境変数
  env: {
    STEP: process.env.MY_STEP,
  },
  // 実行時かつ、サーバサイドで利用できる
  serverRuntimeConfig: {
    MY_SECRET: process.env.MY_SECRET,
  },
  // 実行寺かつ、サーバサイド、クライアントサイドのどちらでも利用できる
  publicRuntimeConfig: {
    API_ENDPOINT: "/my/api/version/1",
  },
};

next.config.jsで設定した値を読み込む方法

例: pages/index.jsで読み込む場合

import getConfig from "next/config";

// next.config.jsで設定した値を取得する
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig();

// クライアントサイド: API_ENDPOINTは参照できるが、MY_SECRETは参照不可になっている。
export default function Index(props) {
  return (
    <div>
      API_ENDPOINT: {publicRuntimeConfig.API_ENDPOINT}
      MY_SECRET: {serverRuntimeConfig.MY_SECRET}
      <pre>{JSON.stringify(props, null, 4)}</pre>
    </div>
  );
}

// サーバサイド: MY_SECRETとAPI_ENDPOINTはどちらも参照可能
export const getServerSideProps = () => {
  return {
    props: {
      MY_SECRET: serverRuntimeConfig.MY_SECRET,
      API_ENDPOINT: publicRuntimeConfig.API_ENDPOINT,
    },
  };
};
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Next.js と Typescript で React-StyleGuidist を使うための設定

概要

Next.jsとTypeScriptでReact-StyleGuidistを利用したかったので調査したときのメモとして残している。

Next.js プロジェクトの作成

create-next-app [prject-name]
cd [project-name]

mkdir src
mv pages src/
mkdir src/components
mkdir src/styleguide

必要なパッケージのインストール

# NextjsでTypeScriptを使うためのパッケージ
yarn add -D @types/node typescript @types/react

# React-StyleguidistをNextjs,TypeScriptと一緒に使うためのパッケージ
yarn add -D react-styleguidist babel-loader react-docgen-typescript

# Bootstrapを使いたかったので追加しているが、必須ではない。
yarn add bootstrap jquery popper.js

styleguide.config.jsの設定

const path = require("path");

module.exports = {
  components: "./src/components/**/*.tsx",
  propsParser: require("react-docgen-typescript").withCustomConfig(
    "./tsconfig.json"
  ).parse,
  styleguideComponents: {
    Wrapper: path.resolve(__dirname, "src/styleguide/Wrapper.tsx"),
  },
  webpackConfig: {
    module: {
      rules: [
        {
          test: /\.tsx?$/,
          exclude: /node_modules/,
          loader: "babel-loader",
        },
        {
          test: /\.css?$/,
          use: ["style-loader", "css-loader"],
        },
      ],
    },
  },
};

src/styleguide/Wrapper.tsxの設定

import React from "react";
import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap";

const Wrapper: React.FC = ({ children }) => {
  return <div>{children}</div>;
};

export default Wrapper;

babel.config.jsの設定

module.exports = {
  presets: ["next/babel"],
  plugins: [],
};

package.jsonの設定

"scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "styleguide": "styleguidist server",
    "styleguide:build": "styleguidist build"
  },

StyleGuistサーバの起動

あとはReactで利用する場合と同じように、
以下のコマンドで起動し、src/componentsにコンポーネントと対応するMDファイルを作成していく。

yarn styleguide
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React入門】Reactとは

初めに

フロントエンド開発初心者がReactの案件に参画することになったため、チュートリアル等で勉強し得た知識をまとめてみました。

Reactとは

Reactはユーザーインターフェース(UI)を構築するためのJavaScriptライブラリです。
UIを「コンポーネント」という小さく独立した部品を組み合わせて構築することができます。

Reactの使用例

実際にReactを使ったサンプルアプリを見てみましょう。
以下は押されたボタンによって値を増減させる簡単なカウンターアプリです。

See the Pen Counter by Amsel (@amsel1676) on CodePen.

サンプルアプリ
class Counter extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      count: 0,
    };
  }

  render(){
    return (
     <div>
       <div className="title">Counter</div>
       <button 
         className="minusButton"
         onClick={() => this.setState({count: this.state.count-1})}
       >
         -
       </button>
       <div className="counter">{this.state.count}</div>
       <button 
         className="plusButton"
         onClick={() => this.setState({count: this.state.count+1})}
        >
         +
        </button>
      </div>
    );
  }
}

ReactDOM.render(
  <Counter />,
  document.getElementById('app')
);

Counterコンポーネント

Counterコンポーネント
class Counter extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      count: 0,
    };
  }

  render(){
    return (
     <div>
       <div className="title">Counter</div>
       <button 
         className="minusButton"
         onClick={() => this.setState({count: this.state.count-1})}
       >
         -
       </button>
       <div className="counter">{this.state.count}</div>
       <button 
         className="plusButton"
         onClick={() => this.setState({count: this.state.count+1})}
        >
         +
        </button>
      </div>
    );
  }
}

上のコードのCounterがReactコンポーネントです。
Counterコンポーネントはpropsというパラメータを受け取り、constructorメソッドで値を初期化させ、renderメソッドで表示するビューの説明書である仮想DOMを返却します。

Counterコンポーネントはstateというオブジェクトでアプリケーションの状態を保持して、状態が変わるごとにその差分を再レンダリングする仕組みになっています。

この状態管理の仕組みにより、上のサンプルアプリではボタンを押した結果がすぐに画面に描画されるようになっています。

コンポーネント呼び出し

コンポーネント呼び出し
ReactDOM.render(
  <Counter />,
  document.getElementById('app')
);

上記がコンポーネントの呼び出し部分となります。
ReactDOM.renderメソッドはCounterコンポーネントが返却した仮想DOMを指定したDOMにレンダリングします。

JSX

上のコードはJavaScriptとHTMLタグが入り混じったような特徴的な見た目をしていますが、これはJSXを用いて書かれているためです。

JSXとは「JavaScript XML」の略で、XML風に作られたJavaScriptの拡張シンタックスです。

JSXのメリット

JSXはあくまで拡張シンタックスであり、JSXで書かれたコードはBabelを通じてJavaScriptの関数呼び出しへと置き換えられます。

つまりReactはJSXを使用せずに書くことが可能です。
JSXを使用せずに書くと以下のようになります。

JSXなし
function Welcome(props){
  return React.createElement(
    'h1',
    null,
    `Welcome ${props.name}`,
  );
}

ReactDOM.render(
  <Welcome name="Tom" />,
  document.getElementById('app')
);

同様のコードをJSXを使用して書くと以下のようになります。

JSXあり
function Welcome(props) {
  return <h1>Welcome, {props.name}</h1>;
}

ReactDOM.render(
  <Welcome name="Tom" />,
  document.getElementById('app')
);

このようにJSXを使用することでHTML風に構造が可視化され、可読性が向上します。

参考

Reactチュートリアル

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React/laravel】componentDidMount()でsetStateする予定のデータを利用してComponentのStateを定義すると失敗する【小説印刷支援サイト】

承前

小説を簡単に同人誌の形にできる印刷できるWebサイトを作りたいと思っている。
今回はその前段階として、印刷する際のプレビュー画面を作成していたときに躓いた話。

事象

直前まで動いていたReactコンポーネントが急にエラーを吐き始めた。

Uncaught TypeError: Cannot read property 'chapterNumber' of undefined
    at RenderUi (index.js:70616)
    at renderWithHooks (index.js:48209)
    at mountIndeterminateComponent (index.js:50888)
    at beginWork (index.js:52002)
    at HTMLUnknownElement.callCallback (index.js:33594)
    at Object.invokeGuardedCallbackDev (index.js:33643)
    at invokeGuardedCallback (index.js:33698)
    at beginWork$1 (index.js:56609)
    at performUnitOfWork (index.js:55560)
    at workLoopSync (index.js:55536)

chapterNumberChapterContentのメンバ。
ChapterContentNovelWithContentsのメンバ。

調査

ChapterContentのインスタンスが空だった。
なんならNovelWithContentsのインスタンスも空だった。
('、3_ヽ)_

やりたかったことと原因

NovelWithContentsのインスタンスは、componetnDidMount()でPHPから持ってきた値を詰めていた。
Console.log()を仕込んでみたところ、componentnDidMount()を通っていないことが分かった。
よって、NovelWithContentsは空で然るべきということが分かった。

axiosで取得したテキストデータに前処理をしてReactコンポーネントに渡したかった。
その前処理の部分で、データが無いクラスのプロパティを参照してエラーを吐いていた。

    componentDidMount() {
        console.log(this.state.novelId+"sssssssssssssssssssssssss");
        axios
            .get(/*API CALL*/)
            .then(response => {
                let data: NovelWithContents = response.data;
                console.log(response.data);
                this.setState({ contentsJson: data });
            })
            .catch(() => {
                console.log("通信に失敗しました。")

            });
    }

対処

失敗した方法

constructorstate初期化後にaxios以下を移してもうまく行かなかった。
renderに移しても同様。

うまく行った方法

色々やった。

  • 前処理後の値をStateにして初期値を与えた。
    • 初回のRender時、即ちaxiosが間に合ってない時に空でエラーを吐かなくなった。
  • 初期化処理をaxiosのfinally()処理に集めた。
    • これによりデータ取得と初期化処理の順番の整合性を取りながら、非同期処理という体は崩さずに済んだ。
  • 上記を可能にするために全体的にリファクタリング
    componentDidMount() {
        axios
            .get(/*API CALL*/)
            .then(response => {
                let data: NovelWithContents = response.data;
                console.log(response.data);
                this.setState({ contentsJson: data });
            })
            .catch(() => {
                console.log("通信に失敗しました。")

            }).finally(()=>{
                let hoge="";
                //前処理。
                });

    }

結局3時間くらいハマってしまった。

反省

  • Reactへの理解度が浅い中で始めたProjectだったので、設計はあとでキチンとやりなおす。

今回実現した機能

小説のページング

小説印刷支援サイト

やや遅れ気味。7月リリースを目指したい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React/laravel】axiosによる非同期のAPI callの結果を待ってからStateに値を入れたかった【小説印刷支援サイト】

承前

小説を簡単に同人誌の形にできる印刷できるWebサイトを作りたいと思っている。
今回はその前段階として、印刷する際のプレビュー画面を作成していたときに躓いた話。

事象

直前まで動いていたReactコンポーネントが急にエラーを吐き始めた。

Uncaught TypeError: Cannot read property 'chapterNumber' of undefined
    at RenderUi (index.js:70616)
    at renderWithHooks (index.js:48209)
    at mountIndeterminateComponent (index.js:50888)
    at beginWork (index.js:52002)
    at HTMLUnknownElement.callCallback (index.js:33594)
    at Object.invokeGuardedCallbackDev (index.js:33643)
    at invokeGuardedCallback (index.js:33698)
    at beginWork$1 (index.js:56609)
    at performUnitOfWork (index.js:55560)
    at workLoopSync (index.js:55536)

chapterNumberChapterContentのメンバ。
ChapterContentNovelWithContentsのメンバ。

調査

ChapterContentのインスタンスが空だった。
なんならNovelWithContentsのインスタンスも空だった。
('、3_ヽ)_

やりたかったことと原因

やりたかったこと

NovelWithContentsがなぜ空なのか

axiosで取得したJSONモデルデータが詰まっている予定だったが、ログを出してみたら問題が分かった。
* componentDidMount()はComponent描画後に呼ばれるため、Component描画時にココで取得する予定の値を参照してしまうとエラーになる。

その後、もう一つの問題も分かった。
* axiosは非同期処理をするので、Constructorなどで事前に値を取得しようとしてもデータ取得処理が間に合うかどうか分からない(間に合わない)

    componentDidMount() {
        console.log(this.state.novelId+"sssssssssssssssssssssssss");
        axios
            .get(/*API CALL*/)
            .then(response => {
                let data: NovelWithContents = response.data;
                console.log(response.data);
                this.setState({ contentsJson: data });
            })
            .catch(() => {
                console.log("通信に失敗しました。")

            });
    }

結論

前処理の部分で、データが無いクラスのプロパティを参照してエラーを吐いていた。

対処

失敗した方法

constructorstate初期化後にaxios以下を移してもうまく行かなかった。
renderに移しても同様。

うまく行った方法

色々やった。

  • 前処理後の値をStateにして初期値を与えた。
    • 初回のRender時、即ちaxiosが間に合ってない時に空でエラーを吐かなくなった。
  • 初期化処理をaxiosのfinally()処理に集めた。
    • これによりデータ取得と初期化処理の順番の整合性を取りながら、非同期処理という体は崩さずに済んだ。
  • 上記を可能にするために全体的にリファクタリング
    componentDidMount() {
        axios
            .get(/*API CALL*/)
            .then(response => {
                let data: NovelWithContents = response.data;
                console.log(response.data);
                this.setState({ contentsJson: data });
            })
            .catch(() => {
                console.log("通信に失敗しました。")

            }).finally(()=>{
                let hoge="";
                //前処理。
                });

    }

結局3時間くらいハマってしまった。

反省

  • Reactへの理解度が浅い中で始めたProjectだったので、設計はあとでキチンとやりなおす。

今回実現した機能

小説のページング

小説印刷支援サイト

やや遅れ気味。7月リリースを目指したい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

サイト構築のタスクを自動化する「Gatsby Recipes」とタスク記述言語としてのMDX

2020年4月、Reactでウェブサイトやアプリケーションを作るGatsbyから「Gatsby Recipes」の発表がありました。(執筆時点ではまだExperimentalな機能です)

Gatsby RecipesはGatsbyでサイトを制作する際に利用するようなタスクを自動化するものです。上記のツイートのようにCLIを経由して使います。
次のようなタスクを自動化します。

  • ページやレイアウトの作成
  • プラグインのインストールと設定
  • TypeScriptの設定

利用するにはGatsbyプロジェクト内で次のコマンドを入力しgatsby, gatsby-cliを最新のものにしてください。

npm install -g gatsby-cli@latest
npm install gatsby@latest

インストールを終えたら、gatsby recipesと入力することで、利用できるレシピを選択できます。
前もって、利用したいレシピが決まっている場合gatsby recipes styled-componentsのように指定が可能です。

レシピを決定すると、ウィザードに従って操作を行うとレシピが実行されます。ライブラリのインストールやgatsby-configの書き換え、必要なファイルの生成などを行ってくれます。

MDXを使ったタスクの記述

Gatsby Recipesは単にサイト構築の支援ツールのように見えますが、一番おもしろいところは上記のようなタスクを記述するのにMDX(Markdown + JSX)を利用しているところです。

MDXはMarkdown内でJSXを仕様できるようにしたフォーマットです。
MDXを使った代表的なものにjxnblk/mdx-deckというスライドツールがあります。MarkdownとJSXを利用してプレゼンテーションを作っていくツールです。

冒頭のツイートのレシピは次のようなMDXを元に動作しています。

 # Setup Theme UI

 This recipe helps you start developing with the [Theme UI](https://theme-ui.com) styling library.

 <Config name="gatsbyjs/add-theme-ui" />

 ---

 Install packages.

 <NPMPackage name="theme-ui" />
 <NPMPackage name="gatsby-plugin-theme-ui" />
 <NPMPackage name="@theme-ui/presets" />

 ---

 Add the plugin `gatsby-plugin-theme-ui` to your `gatsby-config.js`.

 <GatsbyPlugin name="gatsby-plugin-theme-ui" />

 ---

 Write out Theme UI configuration files.

 <File
   path="src/gatsby-plugin-theme-ui/index.js"
   content="https://gist.github.com/KyleAMathews/ab59e200e4f8a1b4109dddb51b2140f9/raw/209a2e7c589766869522b12f7f6cecaf3f7a6f81/index.js"
 />

 <File
   content="export default {}"
   path="src/gatsby-plugin-theme-ui/components.js"
 />

 ---

 **Success**!

 You're ready to get started!

 - Read the docs: https://theme-ui.com
 - Learn about the theme specification: https://system-ui.com

 *note:* if you're running this recipe on the default starter (or any other starter with
 base css), you'll need to remove the require to `layout.css` in the `components/layout.js` file
 as otherwise they'll override some theme-ui styles.

見てわかる通り、Markdownで記述した箇所が文章として、JSXで表示されている部分が実際に実行されている構造になります。
以前からタスク自動化のツールはありましたが、人間に優しくない記述や自由度が低いものが多く存在しました。その課題をうまく解決しようとしている点でGatsby Recipesは非常に面白い試みでしょう。

Recipesに見るNext.jsとの棲み分け

ここからは自分の見解になります。
つい最近、同じくReactをベースにしたフレームワークのNext.js 9.3が公開されました。Next.js 9.3ではStaticにデータを扱う部分が強化され、一見してGatsbyとNext.jsの差が小さくなっています。
しかし、Next.jsは大体何でも作れる万能ナイフ的なフレームワークである一方、Gatsbyは(アプリケーションも作れますが)ウェブサイトに特化したフレームワークです。ウェブサイトに特化している分、プラグインやスターター(テンプレート)が使いやすくエコシステムも強大です。

Gatsby Recipesは一般的なタスクに対応し、よりGatsbyのセットアップは簡単になっていきます。また、RFC段階ではありますが、GatsbyのサイトをいじるためのUI「Gatsby Admin」の動きもあります。これは何でも作れるNext.jsには作りにくく、ウェブサイトに特化したGatsbyだから出来る取り組みです。


Gatsbyは登場して5年ほどたって成熟しているような印象も受けますが、よりよいDXで開発が出来るような方向でさらなる進化をしています。
興味を持った方はGatsby Reciepesはもちろん、Gatsby Adminへ目を向けてみてはいかがでしょうか?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ことばを学ぶ LEARN GATSBY 週間 #2日目

こんにちは !
今日は レイアウト コンポーネント について、学びたいと思います.

レイアウトとコンポーネント

src 内に components フォルダと layouts フォルダを作成します.
src 内には、これで3つのフォルダ (components , layouts , pages ) が存在することになります.

components フォルダには、ヘッダーやフッター、サイドバーなどの 部品 (コンポーネント) を入れます.
layouts フォルダには、ページの レイアウト を入れます.

部品を組み込んだレイアウトをページで使うことによって、コードが見やすくなるため、管理しやすくなります. また一度作ったコンポーネントは使いまわすことができます.

ヘッダーを作る

components フォルダ内に、header.js というヘッダーコンポーネントを作成します.
中身を以下のようにします.

header.js
import React from 'react'
import { Link } from 'gatsby'

const Header = () => {
    return (
        <div>
            <nav>
                <ul>
                    <li>
                        <Link to='/'>Home</Link>
                    </li>
                    <li>
                        <Link to='/bloglist'>BlogList</Link>
                    </li>
                    <li>
                        <Link to='/about'>About</Link>
                    </li>
                </ul>
            </nav>
        </div>
    )
}

export default Header

レイアウトを作る

まず最初に layouts フォルダに common.js ファイルを追加します.
中身を以下のようにします.

common.js
import React from 'react'
import Header from '../components/header'

const Layout = (props) => {
    return (
        <div>
            <Header />
            {props.children}
        </div>
    )
}

export default Layout

Layout を使って index.js about.js の中身を少し変えてみましょう.

index.js
import React from 'react'
import Layout from '../Layouts/common'

const Home = () => {
    return (
        <Layout> 
            <h1>This is Home </h1>
            <h2>Some contents coming soon ...</h2>
        </Layout>
    )
}

export default Home 
about.js
import React from 'react'
import Layout from '../Layouts/common'

const About = () => {
    return (
        <Layout>
            <h1>This is About Page </h1>
            <p>About Page coming soon ...</p>
        </Layout>
    )
}

export default About 

開発用サーバーに移動して ( gatsby develop ) 、どうなっているのか確認してみましょう.

Home リンク、 About リンクを押してみます. Layout である common.js 内の ヘッダーコンポーネント <Header/> の部品は変化せず、{props.children} という要素が変化していることがわかります.

index.js About.js 内の <Layout> で囲まれた部分が common.js 内の {props.children} に挿入されているわけです.

BlogList リンクを押してみると、なにやらエラーが表示されるようです.
pages ディレクトリの中に bloglist.js ファイルを追加してみましょう.
この ブログリストページ を記事一覧ページにしたいと思います !

ここで一つ問題になってくるのが、どうやって記事のデータを取ってくるのかということです.
Gatsby では GraphQL を利用してデータを簡単に取得することができます.

まず、データを扱うための便利な Gatsby にプラグインの設定をしてみましょう.

gatsby-config.jsの設定

gatsby-config.js では、gatsby が提供している様々なプラグインを設定することができます.
現在のディレクトリのどこかに、すべての記事のデータを置いておき、この gatsby-config.js にて、そのパスを指定するだけでデータを GraphQL で参照することができます.
ここでは、記事は マークダウン ファイルとしてあります.

実際にやってみましょう. 全記事のデータはこちらからダウンロードして my-blog ディレクトリに置いてください. ( content という名前です)

gatsby-config.js を開いて、以下のように編集してください.

gatsby-config.js
module.exports = {
  /* Your site config here */
  plugins: [
    'gatsby-plugin-sass' ,
    {
      resolve: 'gatsby-source-filesystem' ,
      options: {
        name: 'content' ,
        path: `${__dirname}/content/`
      }
    },
    'gatsby-transformer-remark',
  ],
}

詳しく見てみましょう.
gatsby-plugin-sass を入れると、スタイルに SASS/SCSS を利用することができるようになります. これはとても便利なので、今のうちに入れておきます.

gatsby-source-filesystem によって、content ディレクトリ内のデータを取得し、
gatsby-transformer-remark によって、取得した マークダウン ファイルを graphQL にて認識できるような形に変換します.

プラグインの設定はこれで終わりです.

実際に、プラグインをインストールしてみます.

npm install --save gatsby-source-filesystem node-sass gatsby-plugin-sass gatsby-transformer-remark

GraphQLを使ってみる

my-blog 内に .env.development ファイルを作成し、その中身を以下のようにします.

GATSBY_GRAPHQL_IDE=playground

ターミナルで env-cmd をインストールします.

npm install --save-dev env-cmd

package.json ファイル内の "develop" のところを以下のように編集します.

"develop": "env-cmd -f .env.development gatsby develop",

そして、 npm run develop にて開発用サーバーを立ち上げます.

http://localhost:8000/___graphql にアクセスしてみましょう !
クールな UI を持った GraphQL Playground が現れました.

左側の画面に以下を打ち込んでください

query {
  allMarkdownRemark {
    edges {
      node {
        frontmatter {
          title
        }
      }
    }
  }
}

真ん中の三角ボタンを押すと、右側の画面に、contnent 内の マークダウン ファイルの情報が示されます. いま、 content 内にある blog フォルダには 6 つの記事があるので、右側の画面には、6 つの記事の情報 (タイトル) がずらーと示されました.

このように、 Gatsby では簡単に、記事の情報を引き出すことができるんです.

まとめ

  • Layoutcomponent を使うことによってコードが見やすくなり、再利用することができる
  • GraphQL を利用することで、データを簡単に引き出すことができる

次回予告

次回は、GraphQL を利用して、今回引き出したデータを実際に ブログリストページ に、表示させたいと思います.

ここまで読んでくださって、ありがとうございました.

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React内でsetIntervalを実現する (LiveScript版)

ReactでsetIntervalが効かなくて困ったので調査
スマートな解決方法が載っている記事がヒットしたので備忘録として残しておく。

参考記事: Making setInterval Declarative with React Hooks

数時間以上React Hooksを使っていたら、
おそらく興味をそそられる問題にぶつかったことでしょう。
setIntervalを使っても思ったようにはいかないのです。

という訳でこの記事のコードをLiveScriptで書き直したのがこちら。
JavaScriptのコードは上記の記事を参考。

functions/use-interval.ls
require! {
  react: {use-ref, use-effect}
}

module.exports = (cb, delay) !->
  saved-cb = use-ref!
  use-effect do
    -> saved-cb.current = cb
    [cb]
  use-effect do
    ->
      if delay isnt null
        id = set-interval _, delay <| -> saved-cb.current!
        return -> clear-interval id
    [delay]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む