つくったもの
テキストエリアに文字を入力しボタンをおすと、
その内容が表示される。というシンプルな機能です。
ファイル構造
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>
で作れます。
詳しくはこちら。
もとから入っているApp.js
の中身を以下のように変更します。
App.js
はこのアプリの機能全体を包む箱となります。
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} />);
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タグで表示するだけ、という機能になります。
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としてコールバックを子にわたし、
それを子コンポーネントの中で実行することで実現します。
わかりにくいのでコードをみてみましょう。
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に変更が生じたらその中にある値をステートに入れる、ということで解決しました。
公式ドキュメントを参考にしました。
気をつけたいこと
ステートはimmutable!
CommentAdder
内で、ステートに新しいコメントをセットするメソッドaddComment
を書いていますが、始めはこのようにpush
を使っていました。
しかし、Reactではステートはimmutableです。
オリジナルの配列を変更してしまうメソッドは使用禁止です。push
は元の配列そのものに、新しい要素を追加してしまうため、つかってはいけません。
私ははじめこのように記述しており、動作はしていましたが、書き直しました。
//こちらはダメな例です
addComment = newComment => {
this.state.list.push(newComment);
this.setState({ list: this.state.list });
};
その他参照ページ
Spread Syntax
Array.protptype.push()
JavaScriptでイミュータブルに配列を操作するメソッドまとめ
以上です。