Flutter の TextField で「？！おえういあ」と入力されてしまう貴方へ

## ？！おえういあ

![flutter_text_field_bug.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135956/51396798-a7d9-8490-dcbc-4d85ee8252aa.gif)




## 原因

`TextField` を公式の [リファレンス](https://api.flutter.dev/flutter/material/TextField-class.html) をもとに実装していたのですが、画面を `StatefulWidget` ↔ `StatelessWidget` と切り替えたりしてゴチャゴチャしているうちに発生しました。

その時のコードの抜粋がこちらです。

```dart
class _MyHomePageState extends State<MyHomePage> {
  String _message = '';

  void _changeMessage(String newValue) {
    setState(() {
      _message = newValue;
    });
  }

  @override
  Widget build(BuildContext context) {

    TextEditingController _controller = TextEditingController(text: _message);

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              _message,
              style: Theme.of(context).textTheme.display1,
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: TextField(
                controller: _controller,
                decoration: InputDecoration(
                  labelText: 'メッセージ',
                  hintText: '入力すると上に表示されるよ',
                ),
                onChanged: _changeMessage,
              ),
            ),
          ],
        ),
      ),
    );
  }
}
```



### おわかりいただけただろうか？

```dart
@override
Widget build(BuildContext context) {

    // 🐛🐛🐛
    TextEditingController _controller = TextEditingController(text: _message);

  // 省略
}
```

このアプリでは文字入力のたびに `_changeMessage` メソッドで `setState` しているんですが、 `setState` したら `build` メソッド呼ばれるんですよね……。

<br>

**「 `TextEditingController` 更新されてる！！」**

<br>

`TextEditingController` はテキストの入力エリアを制御しているので、文字入力のたびにそれが初期化されて、フォーカス位置が初期化されていたみたいです :scream:



## あいうえお！！

![flutter_text_field_success.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135956/f390e280-69b6-a2d9-c5bf-de2a8f78e9aa.gif)

やったね！！


### 修正コード

```dart
class _MyHomePageState extends State<MyHomePage> {
  String _message;
    
  // 🎉🎉🎉
  TextEditingController _controller;

  void _changeMessage(String newValue) {
    setState(() {
      _message = newValue;
    });
  }

  @override
  void initState() {
    super.initState();
    _message = '';
      
    // 🎉🎉🎉
    _controller = TextEditingController(text: _message);
  }

  @override
  void dispose() {
      
    // 🎉🎉🎉
    _controller.dispose();
      
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              _message,
              style: Theme.of(context).textTheme.display1,
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: TextField(
                controller: _controller,
                decoration: InputDecoration(
                  labelText: 'メッセージ',
                  hintText: '入力すると上に表示されるよ',
                ),
                onChanged: _changeMessage,
              ),
            ),
          ],
        ),
      ),
    );
  }
}
```

`TextEditingController` を `build` メソッドの外で作成するように変更しました。



## まとめ

~~こんな事象に普通の人はならんだろｗ~~
`StatefulWidget` のライフサイクルは理解しているつもりでしたが、ゴチャゴチャやってるうちに実装位置を間違えていたようです。

あまりお目にかかることはないと思いますが、発生しても焦らず、 `State` の流れに注意してコードを見るようにしていきましょうね！

初心者向けで、ニッチな内容ですが、どなたかの役に立てれば幸いです :yum: