React (+ Redux) ライフサイクル

公式を読んでいきます! 各セクション TL;DR で

State and Lifecycle

React コンポーネントの状態とライフサイクルの概念について。

Classで書く

React.Component にClockクラスを拡張する。 関数の本体を render() メソッドに定義していて、this.props で値を取得して render()

render() メソッドは、更新が行われるたびに呼び出される。 下記の例では、<Clock /> が、同じDOMノードにレンダリングする限り、 そのClockクラスのインスタンスは1つだけ使用される。

class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2> // this.props で取得
      </div>
    );
  }
}

function tick() {
  ReactDOM.render(
    <Clock date={new Date()} />,
    document.getElementById('root')
  );
}

setInterval(tick, 1000);

Local state を使う

this.props.date と this.state.date して render() する方法

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

ライフサイクルメソッドをクラスに追加する

多くのコンポーネントを持つアプリケーションでは、コンポーネントが破壊されたときにリソースを解放することが非常に重要だ

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }
  
  // DOMにレンダリングされた後にフックが行われる
  componentDidMount() { // タイマーセット(マウント処理)
    this.timerID = setInterval( // this.でアクセスしてtimerID を保存
      () => this.tick(), 
      1000
    );
  }

  componentWillUnmount() { // タイマークリア(アンマウント処理)
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />, // Clockコンポーネントのコンストラクタを呼び出す
  document.getElementById('root')
);

状態を正しく使用する

// wrong
this.state.comment = 'Hello';
// Correct
this.setState({comment: 'Hello'});

状態の更新を非同期で行う

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

// Correct
// 第1引数がstate, 第2引数が更新後のオブジェクト等
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

状態の更新を適用

constructor(props) {
    super(props);
    this.state = {
        posts: [],
        comments: []
    };
}

componentDidMount() {
    fetchPosts().then(response => {
      this.setState({
        posts: response.posts
      });
    });

    fetchComments().then(response => {
      this.setState({
        comments: response.comments
      });
    });
  }

データフローダウン

これは、通常、「トップダウン」または「一方向」データフローと呼ばれます。すべての状態は常に特定のコンポーネントによって所有され、 その状態から派生したデータまたはUIはツリー内のコンポーネントの「下」にしか影響を与えません。 コンポーネントツリーを小道具の滝として想像すると、各コンポーネントの状態は、任意の点でそれを結合する追加の水源のようですが、流れ落ちます。

function FormattedDate(props) {
  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <FormattedDate date={this.state.date} />
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

React.Component

コンポーネントライフサイクル ライフサイクルメソッドの公式チートシート http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

コンポーネントインスタンスを作成してDOMに挿入するときに呼ばれるメソッドについて

constructor() static getDerivedStateFromProps() render() componentDidMount()

※ 非同期レンダリングのライフサイクルについて https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html

状態の変更(更新)

static getDerivedStateFromProps() shouldComponentUpdate() render() getSnapshotBeforeUpdate() componentDidUpdate()

アンマウント

コンポーネントがDOMから削除されるとき componentWillUnmount()

一般的に使われるライフサイクルメソッド

https://reactjs.org/docs/react-component.html#reference

参考: https://reactjs.org/docs/react-component.html

Redux Todos Example

公式: https://redux.js.org/basics/example-todo-list GitHub: https://github.com/reduxjs/redux/tree/master/examples/todos

Redux Todos Example を読み解く 参考: https://intheweb.io/react-redux-todos/

React Redux

【C#】多次元配列とLINQ

探索のメモ化と動的計画法を扱う上での基礎知識として。

配列

配列 - C# によるプログラミング入門 | ++C++; // 未確認飛行 C

2次元配列とLINQ

C#の2次元配列とLINQ - やっさんの雑記

多次元配列をLINQで扱う

多次元配列を LINQ で簡単に扱おう - xin9le.net

拡張メソッドを扱う場合は、静的クラス中に、 第一引数に this キーワードを修飾子として付けた static メソッドを書く 必要がある。
参考:拡張メソッド - C# によるプログラミング入門 | ++C++; // 未確認飛行 C

蟻本/ナップサック問題再帰を使用した例をC#

using System;

namespace Program
{
    class Program
    {
        const int n = 4;
        const int W = 5;

        readonly int[,] data = {
            { 2, 3 },
            { 1, 2 },
            { 3, 4 },
            { 2, 2 }
        };

        static void Main(string[] arg)
        {
            var p = new Program();
            var dp = new int[p.data.GetLength(0) + 1, W + 1];

            var result = p.rec(0, W, ref dp);
            Console.WriteLine("{0}", result);
        }

        public int rec(int i, int j, ref int[,] dp)
        {
            var res = 0;
            if (i == n)
            {
                res = 0;
            }
            else if (j < data[i, 0])
            {
                res = rec(i + 1, j, ref dp);
            }
            else
            {
                res = Math.Max(rec(i + 1, j, ref dp), rec(i + 1, j - data[i, 0], ref dp) + data[i, 1]);
            }

            return dp[i, j] = res;
        }

    }
}

出力: 7

memset での初期化をC#でどう書けばいいのかは分からなかった...

【CircleCI】ASP.NET Core 2.0, xUnit を使用したテスト

前提

環境とコードは、下記の記事を参考に動かします。
【C#】xUnitを使用した単体テスト - 小さいことの積み重ね

CircleCIの導入

こちらの記事を参考にさせていただきました。
GitHubアカウントさえ用意しておけば、簡単に登録できます!
【CircleCI】CircleCI 2.0からはじめる個人での簡単なCI導入方法 - githubとの連携まで - tweeeetyのぶろぐ的めも

config.yml の設定

ASP.NET Core を使った、.ymlファイルの設定です。

version: 2
jobs:
  build:
    docker:
      - image: microsoft/aspnetcore-build:2.0
    steps:
      - checkout
      - run: find .
      - run: dotnet restore
      - run: dotnet build
      - run: dotnet test --no-build [テストディレクトリ]

Start building

CIが回って、 SUCCESS が表示されればOKです。 f:id:danker512:20180415171448p:plain

参考:
Building ASP.NET Core apps on CircleCI // Maartens Notebook
CircleCI を使って C# で書いた AWS Lambda Function のデプロイを自動化する - しばやん雑記
Linux における .NET Core の前提条件 | Microsoft Docs
circle.ymlの書き方 - 冷やしブログはじめました

【C#】xUnitを使用した単体テスト

環境

.NET コマンド ライン ツール (2.1.2)

Product Information:
 Version:            2.1.2

Runtime Environment:
 OS Name:     Mac OS X
 OS Version:  10.12
 OS Platform: Darwin
 RID:         osx.10.12-x64

Microsoft .NET Core Shared Framework Host
  Version  : 2.0.3

ファイル構成

|--PrimeService
|  |--PrimeService.cs
|  |--PrimeService.csproj
|--PrimeService.Tests
|  |--PrimeService.Tests.csproj
|  |--PrimeService_IsPrimeShould.cs
|--TDD.sln

PrimeService_IsPrimeShould.cs

using Xunit;
using Prime.Services;

namespace Prime.UnitTests.Services
{
        public class PrimeService_IsPrimeShould
    {
        private readonly PrimeService _primeService;

        public PrimeService_IsPrimeShould()
        {
            _primeService = new PrimeService();
        }

        [Fact]
        public void ReturnFalseGivenValueOf1()
        {
            var result = _primeService.IsPrime(1);

            Assert.False(result, "1 should not be prime");
        }
    }
}

PrimeService.cs

using System;

namespace Prime.Services
{
    public class PrimeService
    {
            public bool IsPrime(int candidate)
            {
                if (candidate == 1)
                {
                        return false;
                }
                throw new NotImplementedException("Please create a test first");
            }

    }
}

出力

$ cd PrimeService.Tests/
$ dotnet test

テスト実行
Microsoft (R) Test Execution Command Line Tool Version 15.5.0
Copyright (c) Microsoft Corporation.  All rights reserved.

テスト実行を開始しています。お待ちください...
[xUnit.net 00:00:00.4434140]   Discovering: PrimeService.Tests
[xUnit.net 00:00:00.5006950]   Discovered:  PrimeService.Tests
[xUnit.net 00:00:00.5068960]   Starting:    PrimeService.Tests
[xUnit.net 00:00:00.6747760]   Finished:    PrimeService.Tests

テストの合計数: 1。成功: 1。失敗:0。スキップ: 0。
テストの実行に成功しました。
テスト実行時間: 1.5004 秒

参考:
dotnet テストと xUnit を使用した .NET Core での単体テスト C# コード | Microsoft Docs

日時/時間の減算

日時(DateTime構造体)は日付同士の加算はできないが、減算はできる。
時間(TimeSpan構造体)は加減算が可能。

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.IO;
  6 
  7 namespace Program
  8 {
  9     class Program {
 10         static void Main(string[] arg) {
 11             var past = new DateTime(2018, 3, 20);
 12             var now = DateTime.Now;
 13 
 14             var sub = now - past;
 15             var sub2 = now.Subtract(past);
 16 
 17             // var add = now + past;
 18             // Operator `+' cannot be applied to operands of type `System.DateTime' and `System.DateTime'
 19 
 20             Console.WriteLine("sub; {0}", sub);
 21             Console.WriteLine("sub2: {0}", sub2);
 22 
 23             // 10days, 5hours, 6minutes and 1seconds
 24             var tSpan = new TimeSpan(10, 5, 6, 1);
 25 
 26             var tSub = now - tSpan;
 27             var tSub2 = now.Subtract(tSpan);
 28 
 29             var tAdd = now + tSpan;
 30             var tAdd2 = now.Add(tSpan);
 31 
 32             Console.WriteLine("tSub: {0}", tSub);
 33             Console.WriteLine("tSub2: {0}", tSub2);
 34 
 35             Console.WriteLine("tAdd: {0}", tAdd);
 36             Console.WriteLine("tAdd2: {0}", tAdd2);
 37         }
 38     }
 39 }
sub; 1.16:09:16.2632200
sub2: 1.16:09:16.2632200
tSub: 2018/03/11 11:03:15
tSub2: 2018/03/11 11:03:15
tAdd: 2018/03/31 21:15:17
tAdd2: 2018/03/31 21:15:17

【C#, CLI】クラスライブラリを参照、monoでコンパイル実行する

環境

macOS Sierra 10.12.6
mono version 5.8.0.108
NVIM v0.2.2

準備と実行

[1]. コンソールアプリを作る

dotnet new -n Console

[2]. クラスライブラリを作る

dotnet new classlib -n Clazz

dotnet new コマンド - .NET Core CLI | Microsoft Docs

[3]. dllを作成する

csc /target:library /out:Clazz.DLL ../Clazz/Clazz.cs

方法: コマンド ラインを使用してアセンブリを作成および使用する (C# および Visual Basic)

[4]. Console.cs のディレクティブに Clazz を追加する
[5]. mono を使ってコンパイル/実行する

dll を元にコンソールアプリをコンパイル

mcs -r:Clazz.DLL Console.cs

.exeが作成されるので実行

mono Console.exe

dll の作成は dotnet build でもいけるのかな?
dotnet build コマンド - .NET Core CLI | Microsoft Docs

配列とList<T>

配列は「インスタンス生成時に格納できる要素数が決まり、後から変更ができない」、
List<T> は「インタスタンス生成後に、要素を追加、挿入、削除を行える」。

配列、List<T> ともに、IEnumerable<T> インターフェースを持つ。

IEnumerable<T> 型の連続したデータをシーケンスという。
オブジェクトの総称は コレクション と呼び、扱う。

入力

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;      
  4                         
  5 namespace Program       
  6 {       
 13     class Program  
 14     {              
 15         static void Main(string[] args)
 16         {          
 25             var numbers = Enumerable.Repeat(-1, 20).ToList(); // List<T>を同じ値で埋める
 26             var strings = Enumerable.Repeat("(unknown)", 12).ToArray(); // 配列を同じ値で埋める
 27             var array = Enumerable.Range(1, 20).ToArray(); // 配列に連続した値を設定する
 28                              
 29             Console.WriteLine(numbers);
 30             Console.WriteLine(strings);
 31             Console.WriteLine(array);
 32         }                    
 33     }                        
 34 }

出力

System.Collections.Generic.List`1[System.Int32]
System.String[]
System.Int32[]

参考:
実戦で役立つ C#プログラミングのイディオム/定石&パターン:書籍案内|技術評論社