つくったもの
テキストエリアに文字を入力しボタンをおすと、
その内容が表示される。というシンプルな機能です。
ファイル構造
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でイミュータブルに配列を操作するメソッドまとめ
以上です。
