【SwiftUI】@Stateを理解したい

# はじめに
SwiftUIのStateについて学習したので備忘録とアウトプットのつもりで書いてみます。

# 作成するアプリ
ボタンをタップするとランダムに数字が切り替わるシンプルなものを作成してみたいと思います。
![ezgif.com-video-to-gif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/edc3b2ff-3f02-df9e-ffcb-21ec2424874f.gif)

# とりあえず作ってみる
SwiftUIのState以外の部分の説明、解説は極力省いてしまいます。
まずは見た目を作っていきます。

```swift
struct ContentView: View {
    var body: some View {
        VStack {
            Text("\(0)")
                .font(.largeTitle)
                .padding()
            Button(action: {
            }) {
                Text("タップ")
                    .font(.largeTitle)
                    .frame(width: 200, height: 80, alignment: .center)
                    .border(.red)
            }
        }
    }
}
```

TextとButtonを縦に並べたいので、VStackを用います。
TextとButtonの見た目を適当に作成したら次はボタンをタップした時にTextの値を変更して更新します。

```swift
struct ContentView: View {
    
    private var number: Int = 0
    
    var body: some View {
        VStack {
            Text("\(number)")
                .font(.largeTitle)
                .padding()
            Button(action: {
                number = Int.random(in: 1..<10)
            }) {
                Text("タップ")
                    .font(.largeTitle)
                    .frame(width: 200, height: 80, alignment: .center)
                    .border(.red)
            }
        }
    }
}
```

一見、このコードではボタンをタップ(actionのクロージャが呼ばれる)するとnumber変数にランダムに値が格納されるように見えます。しかし、`number = Int.random(in: 1..<10)`の箇所で`Cannot assign to property: 'self' is immutable`というエラーが出てしまいます。これは、`プロパティは'self'がimmutable(変更できないもの)なので設定できない`という意味です。
numberはvarで宣言されているので変更できそうですが、self(この場合はstruct ContentView)で作成されるインスタンスが変更を受け付けてくれません。
これを解決するためにStateを使いましょう。

# Stateとは
[ドキュメント](https://developer.apple.com/documentation/swiftui/state)

Stateを用いることによって
・値の更新を監視し、通知が来たら自動でViewを再描画する。
・struct内のプロパティを変更可能にする。
のメリットがあります。

先ほどのコードをもう一度見てみましょう。
```swift
struct ContentView: View {
    
    private var number: Int = 0
    
    var body: some View {
        VStack {
            Text("\(number)")
                .font(.largeTitle)
                .padding()
            Button(action: {
                number = Int.random(in: 1..<10)
            }) {
                Text("タップ")
                    .font(.largeTitle)
                    .frame(width: 200, height: 80, alignment: .center)
                    .border(.red)
            }
        }
    }
}
```
このコードで問題なのは、
・ボタンをタップし、numberに値が格納されても誰もそれを監視しておらず、Viewの再描画がされずにタップのタイミングでTextが更新されないということ。
・struct内のプロパティの変更が不可であること。
であるため、Stateを使って解決します。

@ Stateをnumber変数につけます。
```swift
struct ContentView: View {
    
    @State private var number: Int = 0
    
    var body: some View {
        VStack {
            Text("\(number)")
                .font(.largeTitle)
                .padding()
            Button(action: {
                number = Int.random(in: 1..<10)
            }) {
                Text("タップ")
                    .font(.largeTitle)
                    .frame(width: 200, height: 80, alignment: .center)
                    .border(.red)
            }
        }
    }
}
```
これによって、ボタンタップ後にnumberに新しく値が格納され、それをStateによって監視しているのでViewが再描画され新しい値が反映されます。

# Property Wrapper(プロパティラッパー)
プロパティラッパーとは、プロパティに対する操作や処理をカプセル化して定義することでキーワードを追加するだけで任意の動作や挙動を行わせることができるデータ構造です。
すでに定義されている@ Stateはプロパティラッパーの一つです。
前述の通り、@ Stateはプロパティの値の変更を監視し、Viewを再描画してくれることとプロパティの変更を可能にしてくれる特徴を持ちます。
@ Bindingや@ Environmentなど他にもたくさんあるようです。そのうち書いてみたいなと思います。

# おわりに
SwiftUI学習始めたばかりなので、間違ってる点がありましたらTwitterまたはコメントで"やさしく"教えてくださいませ。