『React』 +『Redux』 + 『Firebase』でLINE風のChat機能を作ろう！ 【Component編】

#はじめに
前回の記事では

- create-react-app
- パッケージのインストール
- Firebaseとの紐付けを行いました。

今回は、__Material-UI__を用いてComponentを作成していきましょう！

前回の記事
[『React』 +『Redux』 + 『Firebase』でLINE風のChat機能を作ろう！ 【準備編】](https://qiita.com/micropig3402/items/5a24f35f68bb6b3c8e81)

#実装してみよう！

##1. 使いたいComponentをMaterial-UIから探す

[https://material-ui.com/](https://material-ui.com/)にアクセスし、自分の好みのデザインのコンポーネントを探しましょう！

###[ヘッダー](https://material-ui.com/components/app-bar/#app-bar)
<img width="859" alt="スクリーンショット 2019-05-31 10.58.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/343290/9c5feaea-cadc-278d-7d5a-807ffd732efe.png">


###[メッセージ入力欄](https://material-ui.com/components/text-fields/#textfield)
<img width="856" alt="スクリーンショット 2019-05-31 11.05.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/343290/6caab480-6863-d241-bb7e-2fae1e84a53e.png">



###[メッセージ送信ボタン](https://material-ui.com/components/buttons/#buttons)
<img width="852" alt="スクリーンショット 2019-05-31 10.57.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/343290/1531c629-520d-dfff-326a-ccc87673c6ad.png">


###[メッセージ表示欄](https://material-ui.com/components/lists/#lists)
<img width="857" alt="スクリーンショット 2019-05-31 11.06.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/343290/ff726d12-f857-5b56-49e7-a9344fe1537a.png">

今回は以上の4つのコンポーネントを用いてアプリを作成しました。

##2. Material-UIのComponentを自分なりにアレンジする
使いたいComponentが決まったら、それをベースにして自分なりに少しアレンジを加えてみましょう！

###ページ全体

```react:src/App.js
import React, {Component} from 'react';

import {connect} from 'react-redux';

import AlignItemsList from './components/AlignItemsList';
import ButtonAppBar from './components/ButtonAppBar.js';
import TextInput from './components/TextInput.js';

import {firebaseDb} from './firebase';

import './styles/App.css';

const messagesRef = firebaseDb.ref('messages');

class App extends Component {
  render() {
    return (
      <React.Fragment>
        <ButtonAppBar />
        <div className="App">
          <AlignItemsList />
          <TextInput value="メッセージを入力" />
        </div>
      </React.Fragment>
    );
  }
}

export default App;
```

```css:src/styles/App.css
.App{
  margin: 0 auto;
  max-width: 500px;
}

@media screen and (max-width:520px) { 
  /*　画面サイズが520pxからはここを読み込む　*/
  .App{
    margin: 0 20px;
  }
}

.App ul {
  margin: 10px auto;
}

.App ul li {
  padding-left: 0;
  display: flex;
  align-items: center;
}

.App ul .MuiDivider-inset{
  margin-left: 57px;
}

.App ul li .MuiListItemAvatar-alignItemsFlexStart {
  margin-top: 0;
}
```

###ヘッダー

```react:src/components/ButtonAppBar.js
import React from 'react';
import {makeStyles} from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import IconButton from '@material-ui/core/IconButton';
import MenuIcon from '@material-ui/icons/Menu';
import '../styles/ButtonAppBar.css';

const useStyles = makeStyles(theme => ({
  root: {
    flexGrow: 1,
  },
  menuButton: {
    marginRight: theme.spacing(2),
  },
  title: {
    flexGrow: 1,
  },
}));

function ButtonAppBar() {
  const classes = useStyles();

  return (
    <div className={classes.root}>
      <AppBar position="static">
        <Toolbar>
          <IconButton
            edge="start"
            className={classes.menuButton}
            color="inherit"
            aria-label="Menu">
            <MenuIcon />
          </IconButton>
          <Typography variant="h4" className={classes.title}>
            PigTalk
          </Typography>
          <Button color="inherit">Login</Button>
        </Toolbar>
      </AppBar>
    </div>
  );
}

export default ButtonAppBar;
```

```css:src/styles/ButtonAppBar.css
h4 {
    text-align: center;
}
```

###メッセージ入力欄

```react:src/components/TextInput.js
import React, {Component} from 'react';

import TextField from '@material-ui/core/TextField';
import '../styles/TextInput.css';
import SendButtons from './SendButton';

import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';

class TextInput extends Component {
  render() {
    return (
      <React.Fragment>
        <form className="wrap" noValidate autoComplete="off">
          <TextField
            id="standard-text"
            label="メッセージを入力"
            className="text"
            margin="normal"
          />
          <SendButtons />
        </form>
      </React.Fragment>
    );
  }
}

export default TextInput;
```

```css:src/styles/TextInput.css
.wrap {
    display: flex;
    justify-content: center;
}

.wrap .text {
    width: 80%;
}

.wrap button {
    margin-top: 24px;
    margin-right: 0;
    width: 20%;
}
```

###メッセージ送信ボタン

```react:src/components/SendButton.js
import React from 'react';

import Button from '@material-ui/core/Button';
import {makeStyles} from '@material-ui/core/styles';
import Icon from '@material-ui/core/Icon';

const useStyles = makeStyles(theme => ({
  button: {
    margin: theme.spacing(1),
  },
  leftIcon: {
    marginRight: theme.spacing(1),
  },
  iconSmall: {
    fontSize: 20,
  },
}));

function SendButtons() {
  const classes = useStyles();

  return (
    <Button variant="contained" color="primary" className={classes.button}>
      <Icon>send</Icon>
    </Button>
  );
}

export default SendButtons;
```

###メッセージ表示欄

```jsx:src/components/AlignItemsList.js
import React from 'react';
import {makeStyles} from '@material-ui/core/styles';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import Divider from '@material-ui/core/Divider';
import ListItemText from '@material-ui/core/ListItemText';
import ListItemAvatar from '@material-ui/core/ListItemAvatar';
import Avatar from '@material-ui/core/Avatar';

const useStyles = makeStyles(theme => ({
  root: {
    backgroundColor: theme.palette.background.paper,
  },
  inline: {
    display: 'inline',
  },
}));

function AlignItemsList() {
  const classes = useStyles();

  return (
    <List className={classes.root}>
      <ListItem alignItems="flex-start">
        <ListItemAvatar>
          <Avatar
            alt="Remy Sharp"
            src="https://hellogiggles.com/wp-content/uploads/2015/03/11/micro-pig-LondonPignic.jpg"
          />
        </ListItemAvatar>
        <ListItemText primary="Hello World" />
      </ListItem>
      <Divider variant="inset" component="li" />
    </List>
  );
}

export default AlignItemsList;
```

###送信ボタンのIconを使うために

```public/index.html
<head>
    ...
    <!-- Google Icon -->
    <link
      rel="stylesheet"
      href="https://fonts.googleapis.com/icon?family=Material+Icons"
    />
    ...
</head>
```

# 実装完了
<img width="669" alt="スクリーンショット 2019-05-31 11.43.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/343290/f7a4c0f9-f10f-6af8-4701-5b4a8ba7ba66.png">

#次回は

- __『Redux』__を用いて__action__、__reducer__、__store__を定義し、状態管理を実装
- __『Firebase』__の__『Realtime Database』__とのデータの受け渡しの実装

をします！

#リファレンス
- [Material-UI](https://material-ui.com/)
- [App Bar with buttons](https://material-ui.com/components/app-bar/#app-bar)
- [TextField](https://material-ui.com/components/text-fields/#textfield)
- [Buttons with icons and label
](https://material-ui.com/components/buttons/#buttons)
- [Align list items](https://material-ui.com/components/lists/#lists)