React 初心者向け「簡単Blog」- Blog一覧・検索編

# 簡単Blog
Blogのリスト・検索：登録・編集・削除までを行う機能を実装します。
今日はBlogの親コンポーネントとBlogの内容を表示する子コンポーネントを作って検索までやってみます。
Blogはユーザー名、タイトル、Blog内容で構成されています。

![スクリーンショット 2019-10-09 0.06.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108475/f8343ed0-ebb5-2e91-bd20-17567bd0fb2f.png)


#コンポーネント構成
![Untitled Diagram-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108475/6539a523-3ff2-7d13-51e8-24201ef8c12e.png)


# react-bootstrap設置
react-bootstrapを少し使ってみました。
npmで設置してImportするだけで簡単に使えました。
Bootstrapの説明は省略します。興味ある方は以下のリンク参照してください。
https://react-bootstrap.netlify.com/getting-started/introduction/

```
npm install react-bootstrap bootstrap
```

# Blogの親コンポーネント実装
stateで状態を管理
子コンポーネントにPropsを利用して状態を渡す。
### constructorにstate定義
keyword：検索文字列
blogData: 複数のBlogを表示するように配列にする

```
constructor(props) {
      super(props)
　　　 this.state = {
        keyword: "",
        blogData: [
          {
            user_name: "吉田",
            title: "おはよう",
            content: "朝はおはよう〜"
          },
          ...
        ]
      }
```

### eventハンドラー追加(検索文字が入力される時にkeyword状態を変更する事でViewが更新される)
```
　　constructor(props) {
      ...
      this.onChange = this.onChange.bind(this);
　　}
    onChange(e) {
        this.setState({
            keyword: e.target.value
        })
    }
```

### render()実装
複数のコンポーネントデータからKeyword状態でFilterしたBlogInfoデータのコンポーネントを生成。
SearchテキストのValueに`this.state.keyword`を設定しているのでonChangeの`e.target.value`で検索文字列が変わるたびにStateに変更を持たせて、Renderingさせる。


```
    render() {
        const getComponents = (data) => {
            data = data.filter(
                (blog) => {
                    return blog.title.toLowerCase().indexOf(this.state.keyword.toLowerCase()) > -1;
                });
            data.sort();
            return  data.map((blog) => {
                return (
                <div>
                <BlogInfo blog={blog}></BlogInfo>
                </div>
                )
            })
        }
        return (
            <div>
            <h1>Blog</h1>
            <FormControl type="text" placeholder="Search" className="mr-sm-2" value={this.state.keyword} onChange={this.onChange}/>
            <div>{getComponents(this.state.blogData)}</div>
            </div>
        )
    }
```

### Blog.js(親コンポーネントコード)
```react:Blog.js
import React, { Component } from 'react'
import BlogInfo from './BlogInfo'
import {FormControl} from 'react-bootstrap'

export default class Blog extends Component {
    constructor(props) {
      super(props)
      this.state = {
        keyword: "",
        blogData: [
          {
            user_name: "吉田",
            title: "おはよう",
            content: "朝はおはよう〜"
          },
          {
            user_name: "高橋",
            title: "こんにちは",
            content: "昼はこんにちは〜"
          },
          {
            user_name: "木村",
            title: "こんばんは",
            content: "夜はこんばんは〜"
          }
        ]
      }
      this.onChange = this.onChange.bind(this);
    }


    onChange(e) {
        this.setState({
            keyword: e.target.value
        })
    }

    render() {
        const getComponents = (data) => {
            data = data.filter(
                (blog) => {
                    return blog.title.toLowerCase().indexOf(this.state.keyword.toLowerCase()) > -1;
                });
            data.sort();
            return  data.map((blog) => {
                return (
                <div>
                <BlogInfo blog={blog}></BlogInfo>
                </div>
                )
            })
        }
        return (
            <div>
            <h1>Blog</h1>
            <FormControl type="text" placeholder="Search" className="mr-sm-2" value={this.state.keyword} onChange={this.onChange}/>
            <div>{getComponents(this.state.blogData)}</div>
            </div>
        )
    }
}

```

# BlogInfo（子コンポーネント実装）
親コンポーネントで以下の様に`blog`と言う名前のPropsにBlog状態を渡している。
`<BlogInfo blog={blog}></BlogInfo>`
子コンポーネントからは`{this.props.blog.user_name}`でそのBlog状態を受け取ることができる。
その情報を子コンポーネントはRenderingする。
CardはBootStrapのコンポーネント。

```react:BlogInfo.js
import React, { Component } from 'react'
import {Card} from 'react-bootstrap'

export default class  BlogInfo  extends Component{
  render() {
    return(
        <Card border="info" style={{ width: '18rem' }}>
            <Card.Header>{this.props.blog.user_name}</Card.Header>
            <Card.Body>
            <Card.Title>{this.props.blog.title}</Card.Title>
            <Card.Text>
             内容：　{this.props.blog.content}
            </Card.Text>
            </Card.Body>
        </Card>
    )
  }
}
```

# App.js
```react:App.js
import React, { Component } from 'react'
import './App.css';
import Blog from './components/Blog';

class App extends Component {
  render() {
    return (
      <Blog></Blog>
    );
  }
}

export default App
```

# 完成
![Blog.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108475/6ac5fb75-c8a4-eaef-9006-e8bfdae39e3d.gif)