React練習) テキストエリアに文字を入力しボタンをおすとその内容が表示される。というシンプルなアプリ

## つくったもの
テキストエリアに文字を入力しボタンをおすと、
その内容が表示される。というシンプルな機能です。

![](https://media.giphy.com/media/j5gtDnHiVIPgfQ3avu/giphy.gif)

## ファイル構造
```
project/
　├ node_modules/
　├ src/
　|  ├ App.css 
　|  ├ App.js 
　|  ├ index.css  
　|  ├ index.js 
　|  ├ serviceWorkers.js   
　│　└ components/
　│　　　├ Comment/
　|　　　|　　　└ Comment.jsx
　│　　　├ CommentAdder/
　|　　　|  　　└ CommentAdder.jsx
　│　　　└ CommentsList/
　|　　　　　 　└ CommentsList.jsx
　├ .gitignore
　├ README.md
　├ yarn.lock
　└ package.json 
```



## 手順
###### 1 `create-react-app`を導入。`App.js`を作成
```
yarn global add create-react-app
create-react-app <project>
```
で作れます。
詳しくは[こちら](https://yarnpkg.com/lang/en/docs/cli/create/)。

もとから入っている`App.js`の中身を以下のように変更します。

`App.js`はこのアプリの機能全体を包む箱となります。

```JavaScript
import React from "react";
import "./App.css";
import CommentsList from "./components/CommentsList/CommentsList";
import CommentAdder from "./components/CommentAdder/CommentAdder";

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { list: [] };
  }

  addComment = newComment => {
    this.setState({ list: [...this.state.list,newComment] });
  };

  render() {
    return (
      <div className="App">
        <CommentAdder onAddComment={this.addComment} />
        <CommentsList list={this.state.list} />
      </div>
    );
  }
}

export default App;
``` 

###### 2 `CommentsList.jsx`を作成

`CommentsList.jsx`は、コメントが表示される箱となります。

`props` とはpropertiesの省略形で、親コンポーネントから渡されてくるオブジェクトのことです。親である`App.js`で以下のラインがpropsを設定している箇所になります。

` <CommentsList list={this.state.list} />`

`App.js`のthis.stateをみてください。そこにある配列を渡しています。
配列なのでArrayメソッドが使えます。

配列の要素が実際に画面に出現するコメントになります。

コメントを表示させる機能は別ファイル`Comment.jsx`として作成し、
`App.js`からみて孫コンポーネント、`CommentsList.jsx`からみて子コンポーネントとしてネストします。

表示させたいのはmapメソッドでループされている全ての要素一つ一つなので、
propsの設定の仕方は以下のようになります。
`   const comments = props.list.map(comment => <Comment comment={comment} />);`

```JavaScript
import React from "react";
import Comment from "../Comment/Comment";

const CommentsList = props => {
  const comments = props.list.map(comment => <Comment comment={comment} />);
  return (
    <div className="commentsArea">
      <ul>{comments}</ul>
    </div>
  );
};

export default CommentsList;
```


###### 3 `Comment.jsx`を作成

`Comment.jsx`は、一つずつのコメントそのものとなります。
これは`CommentsList.jsx` から渡されてきたpropsに入っているcommentをただpタグで表示するだけ、という機能になります。

```JavaScript
import React from "react";

const Comment = props =>{
    return (
      <div>
        <p>{props.comment}</p>
      </div>
    );
} 
  
export default Comment;
```

###### 4 `CommentAdder.jsx`を作成

textareaに変更が生じたら、`CommentAdder`のステートに格納する。
ボタンが押されたら、その格納されているステートを、親コンポーネントである`App.js`に渡す。
ということをしています。

ここで問題なのが、Reactではデータはpropsを用いてデータを親から子方向に渡していきますが、逆方向、子から親方向へはpropsをつかって渡すことができません。

そのときは、親コンポーネントからpropsとしてコールバックを子にわたし、
それを子コンポーネントの中で実行することで実現します。

わかりにくいのでコードをみてみましょう。

```JavaScript
import React from "react";

class CommentAdder extends React.Component {
  constructor(props) {
    super(props);
    this.state = { addedComment: "" };
  }

  onChange = event => {
    this.setState({ addedComment: event.target.value });
  };

  render() {
    return (
      <div className="adderContainer">
        <textarea
          className="textArea"
          cols="30"
          rows="3"
          value={this.state.addedComment}
          onChange={this.onChange}
        ></textarea>
        
        <button
          className="button"
          onClick={() => {
            this.props.onAddComment(this.state.addedComment); //ここで親から渡されたメソッドを実行
            this.setState({addedComment:""})　//textareaを空にする
          }}
        >
          ADD
        </button>
      </div>
    );
  }
}

export default CommentAdder;
```


 

## つまづいたところ

#### textareaに入力した値を描画すること
`onChange`メソッドを作成し、textareaに変更が生じたらその中にある値をステートに入れる、ということで解決しました。

[公式ドキュメント](https://reactjs.org/docs/forms.html)を参考にしました。


#### 気をつけたいこと
ステートはimmutable! 

`CommentAdder` 内で、ステートに新しいコメントをセットするメソッド`addComment`を書いていますが、始めはこのように`push`を使っていました。

しかし、Reactではステートはimmutableです。
オリジナルの配列を変更してしまうメソッドは使用禁止です。`push`は元の配列そのものに、新しい要素を追加してしまうため、つかってはいけません。

私ははじめこのように記述しており、動作はしていましたが、書き直しました。

```JavaScript   
//こちらはダメな例です
addComment = newComment => {
    this.state.list.push(newComment);
    this.setState({ list: this.state.list });
  };
```

#### その他参照ページ
[Spread Syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax)
[Array.protptype.push()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/push)
[JavaScriptでイミュータブルに配列を操作するメソッドまとめ](https://noah.plus/blog/007/)


以上です。