20191002のReactに関する記事は3件です。

react-chartjs-2とChart.jsを使ってグラフを作ってみた

最近Reactを勉強しており、その際にグラフを作りたいと思いました。react-chartjs-2の提供もされていたので、今回は「Chart.js」を使用することにしました。

今回は線グラフですが、他にも円グラフや棒グラフなど色々あります。
https://jerairrest.github.io/react-chartjs-2/
また詳しい導入法は公式ドキュメントから確認できます。
https://github.com/jerairrest/react-chartjs-2

完成時のイメージとコードは下です。
スクリーンショット 2019-10-02 21.18.14.png
必要となる「react-chartjs-2」と「chart.js」のインストール

yarn add react-chartjs-2 chart.js
App.js
import React from "react";
import LineExample from './Line';

function App() {
  return (
    <div className='App'>
      <LineExample />
    </div>
  );
}

export default App;
Line.js
import React from 'react';
import {Line} from 'react-chartjs-2';

const data = {
  labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
  datasets: [
    {
      label: 'My First dataset',
      fill: true,
      lineTension: 0.1,
      backgroundColor: 'rgba(75,192,192,0.4)',
      borderColor: 'rgba(75,192,192,1)',
      borderCapStyle: 'round',
      borderDash: [],
      borderDashOffset: 0.0,
      borderJoinStyle: 'square',
      pointBorderColor: 'rgba(75,192,192,1)',
      pointBackgroundColor: '#eee',
      pointBorderWidth: 10,
      pointHoverRadius: 5,
      pointHoverBackgroundColor: 'rgba(75,192,192,1)',
      pointHoverBorderColor: 'rgba(220,220,220,1)',
      pointHoverBorderWidth: 1,
      pointRadius: 1,
      pointHitRadius: 10,
      data: [3, 10, 21, 31, 34, 40, 48]
    }
  ]
};

const LineExample = () => {
  return (
    <div>
      <h2>Line Example</h2>
      <Line data={data} />
    </div>
  );
}

export default LineExample;

上の例では一つの線グラフでしたが、複数のグラフを表示することもデザインを加えることもできます。
スクリーンショット 2019-10-02 21.17.12.png
複数のグラフを表示する方法がわからなかった時に参考になったstackoverflowも一緒にのせておきます。
create a multi line chart using Chart.js

参考文献
react-chartjs-2
react-chartjs-2のgithub
create a multi line chart using Chart.js

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

gatsby: command not found とエラーが出た時の対応

一般的なgatsbyのことはじめ

公式の手順通りにインストールしてくる
https://www.gatsbyjs.org/docs/quick-start

npm install -g gatsby-cli

gatsby: command not found と上手くいかない時がある

上記のコマンドではPCの設定などによっては上手くインストールできない場合があるようです。
そのためyarnを使用してインストールし直すと上手くいく。

yarnのインストールはこちらから
https://yarnpkg.com/lang/en/docs/install/#mac-stable

sudo yarn global add gatsby-cli

上記のコマンドでやり直したところ上手くいきました。

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

React-Reduxが難しい? それは過去の話だ! ~ ToDoアプリを最小限の労力で記述する ~

Reduxが難しい? それは過去の話だ! ~ ToDoアプリを最小限の労力で記述する ~

 React-Reduxを簡単に利用するためのパッケージ@jswf/redux-moduleを利用して、最小限の労力でToDoアプリを作成するという内容です。

※追記
 @jswf/redux-moduleの使い方は以下記事で、もう少し短いソースにて確認できます
 React-ReduxだけどReducerもActionも書かず、Dispatchすら使わず、データも何となく受け取れるようにする方法

最初に

 プログラムはファイル一つだけにまとめました。
 内容は以下のように構成されています。

  • データ構造の定義
  • データ操作用クラスの作成
  • データ入力用コンポーネント
  • データ表示用コンポーネント

 今回はReduxラッパーの機能を使うため、データの入力と表示はコンポーネントは分けてあります。
 ここで見ていただきたいのは、propsもuseStateも使っていないということです。
 全てのデータはReduxのStore上に格納されます。
 しかしReduxを使う上での前提となるFlux的な定義は一切書く必要がありません。
 ReduxModuleクラスを継承することによって、読み書き全ての手続きがReduxModuleで定義されているsetStateとgetStateメソッドに集約されます。

作ったもの

実働サンプル
GitHub上のソース
screenshot.gif

ソースコード

index.tsx
import React from "react";
import * as ReactDOM from "react-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";
import {
  ModuleReducer,
  useModule,
  ReduxModule
} from "@jswf/redux-module";

/**
 *データ構造の定義(TypeScript使用時)
 *
 * @export
 * @interface TodoState
 */
interface TodoState {
  //入力中データの保持
  input: {
    title: string;
    desc: string;
  };
  //TODOリスト
  todos: {
    id: number;
    title: string;
    desc: string;
    done: boolean;
  }[];
  //TODOのID附番表index
  index: number;
}

/**
 *Todoデータ管理用クラス
 *
 * @export
 * @class TodoModule
 * @extends {ReduxModule<TestState>}
 */
export class TodoModule extends ReduxModule<TodoState> {
  //初期値
  protected static defaultState: TodoState = {
    todos: [],
    input: { title: "", desc: "" },
    index: 0
  };
  /**
   *ToDoリストを返す
   *
   * @returns
   * @memberof TodoModule
   */
  public getTodos() {
    return this.getState("todos")!;
  }
  /**
   *ToDoを追加(追加データはStoreに入っているので引数不要)
   *
   * @memberof TodoModule
   */
  public addTodo() {
    //indexのインクリメント
    const index = this.getState("index")! + 1;
    this.setState({ index });
    //必要データの読み出し
    const title = this.getState("input", "title")!;
    const desc = this.getState("input", "desc")!;
    //todoを追加
    const todos = [
      ...this.getState("todos")!,
      { id: index, title, desc, done: false }
    ];
    this.setState({ todos })!;
  }
  /**
   *ToDoの状態管理
   *
   * @param {number} id
   * @param {boolean} done
   * @memberof TodoModule
   */
  public updateDone(id: number, done: boolean) {
    const srcTodos = this.getState("todos")!;
    //状態の書き換え
    const todos = srcTodos.map(todo =>
      todo.id === id ? { ...todo, done } : todo
    );
    this.setState({ todos });
  }
  /**
   *ToDoの削除
   *
   * @param {number} id
   * @memberof TodoModule
   */
  public remove(id: number) {
    const srcTodos = this.getState("todos")!;
    //削除データを除外
    const todos = srcTodos.filter(todo => todo.id !== id);
    this.setState({ todos });
  }
}


/**
 *入力フォームコンポーネント
 *
 * @returns
 */
function FormComponent() {
  const todoModule = useModule(TodoModule);
  return (
    <div style={{ textAlign: "center" }}>
      <div>
        <div>タイトル</div>
        <input
          style={{ width: "20em" }}
          value={todoModule.getState("input", "title")!}
          onChange={e => todoModule.setState(e.target.value, "input", "title")}
        />
        <div>説明</div>
        <textarea
          style={{ width: "20em", height: "5em" }}
          value={todoModule.getState("input", "desc")!}
          onChange={e => todoModule.setState(e.target.value, "input", "desc")}
        />
        <div>
          <button onClick={() => todoModule.addTodo()}>Todoを作成</button>
        </div>
      </div>
    </div>
  );
}

/**
 *ToDo出力コンポーネント
 *
 * @returns
 */
function TodoListComponent() {
  const todoModule = useModule(TodoModule);
  const todos = todoModule.getState("todos")!;
  return (
    <div style={{ display:"flex",flexDirection: "column" ,alignItems:"center"}}>
      {todos.map(todo => (
        <div
          key={todo.id}
          style={{
            display: "inline-block",
            width: "20em",
            marginTop: "1em",
            border: "solid 1px",
            textAlign:"center"
          }}
        >
          <div>
            {todo.id}:{todo.title}{" "}
            <span
              style={{ cursor: "pointer" }}
              onClick={() => todoModule.updateDone(todo.id, !todo.done)}
            >
              {todo.done ? "完了" : "未完了"}
            </span>
            {todo.done && (
              <span
                style={{ cursor: "pointer" }}
                onClick={() => todoModule.remove(todo.id)}
              >
                削除
              </span>
            )}
          </div>
          <div>{todo.desc}</div>
        </div>
      ))}
    </div>
  );
}

//Reduxに専用のReducerを関連付ける
//他のReducerと併用することも可能
const store = createStore(ModuleReducer);
ReactDOM.render(
  <Provider store={store}>
    <FormComponent />
    <TodoListComponent />
  </Provider>,
  document.getElementById("root") as HTMLElement
);

まとめ

 ほぼReduxの影や形が消え去っています。
 今回の内容はコンポーネント間の連係や、データをStoreに集約することが目的であれば、かなり便利に使えると思います。

 パフォーマンスを考えて作る場合は、副作用の影響範囲を最小限に抑えるためデータ操作用のクラスを細分化したり、書き込みのみしか利用しないコンポーネント上ではwriteOnly属性を付けたりとチューニングが必要になりますが、それは別の記事で解説を入れたいと思います。

 Reduxの定義に疲れ果てた方はぜひ使ってみてください。

リンク

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