Reactで画面遷移先に値を送る

React初心者向けの記事です。
コンポーネント間での値の受け渡しについて試行錯誤したものをまとめました。

まず最初のページと画面遷移先のページを用意します。
画面遷移は`react-router-dom`を使用して行います。

```React:FirstPage.js
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';

class FirstPage extends Component {

  constructor(props){
    super(props);
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick(){
    this.props.history.push('/secondpage')
  }

  render() {
    return (
      <div>
        最初のページ
	<br/>
        <button onClick={this.handleClick}>画面遷移します</button>
      </div>
    );
  }
}

export default withRouter(FirstPage)

```

```React:SecondPage.js
import React, { Component } from 'react';

export default class SecondPage extends Component {
  render() {
    return (
      <div>
        <p>画面遷移先のページ</p>
      </div>
    );
  }
}

```

ボタンを押したら画面遷移するというだけのシンプルなものです。

ルーティングはこんな感じ。

```React:Routes.js
import {Route, Switch} from 'react-router-dom';
import React, { Component } from 'react';
import FirstPage from './FirstPage';
import SecondPage from './SecondPage';

export default class Routes extends Component {
    render() {
        return (
            <div>
                <Switch>
                    <Route exact={true} path='/firstpage' component={FirstPage}/>
                    <Route exact={true} path='/secondpage' component={SecondPage}/>
                </Switch>
            </div>
        );
    }
}

```

それではコンポーネント間での値の受け渡しについて考えていきましょう。

最初のページにテキストボックスを用意します。
このテキストボックスに入力された値を画面遷移先に渡します。

```React:FirstPage.js
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';

class FirstPage extends Component {

  constructor(props){
    super(props);
    this.state = {
      text: '',
    }

    this.handleChange = this.handleChange.bind(this)
    this.handleClick = this.handleClick.bind(this)
  }

  handleChange(e){
    this.setState({
      text: e.target.value
    })
  }

  handleClick(){
    this.props.history.push('/secondpage')
  }

  render() {
    return (
      <div>
        最初のページ
	<br/>
        <input type='text' value={this.state.text} onChange={this.handleChange}></input>
        <p>{this.state.text}</p>
        <button onClick={this.handleClick}>画面遷移します</button>
      </div>
    );
  }
}

export default withRouter(FirstPage)

```

##案１　react-router-domの機能を使う

下記のように書けば遷移先に値を受け渡すことができます。

```React
    this.props.history.push({
      pathname: '/secondpage',
      state: { text: this.state.text }
  });
```

受け取った値は

```React
this.props.location.state.text
```

で使用できます。

```React:FirstPage.js
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';

class FirstPage extends Component {

  constructor(props){
    super(props);
    this.state = {
      text: '',
    }

    this.handleChange = this.handleChange.bind(this)
    this.handleClick = this.handleClick.bind(this)
  }

  handleChange(e){
    this.setState({
      text: e.target.value
    })
  }

  handleClick(){
    this.props.history.push({
      pathname: "/secondpage",
      state: { text: this.state.text }
  });
  }

  render() {
    return (
      <div>
        最初のページ
        <br/>
        <input type='text' value={this.state.text} onChange={this.handleChange}></input>
        <p>{this.state.text}</p>
        <button onClick={this.handleClick}>画面遷移します</button>
      </div>
    );
  }
}

export default withRouter(FirstPage)

```

```React:SecondPage.js
import React, { Component } from 'react';

export default class SecondPage extends Component {
  render() {
    return (
      <div>
        <p>画面遷移先のページ</p>
        <p>{this.props.location.state.text}</p>
      </div>
    );
  }
}

```

##案2　Reduxを使う
Reduxはstoreという場所にstateを保存してくれます。
これを使うことでいつでもstateの取得、更新が可能になります。便利。
Reduxの詳しい説明は今回は割愛します。

Reduxを使う場合は下記の２つのパッケージをインストールしましょう。
`redux `
`react-redux`

まずはstoreを作ります。

```React:index.js
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter} from 'react-router-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import './index.css';
import reducer from './reducers';
import Routes from './containers/Routes';

const store = createStore(reducer);

ReactDOM.render(
  <Provider store={store}>
    <BrowserRouter>
      <Routes />
    </BrowserRouter>
  </Provider>,
  document.getElementById('root'));

```

次にactionを書きます。

```React:action.js
export const SEND_TEXT = 'SEND_TEXT';

export const inputText = (text) => ({
  type: SEND_TEXT,
  text,
})

```

そしてReducer。Reducerは実装していくうちにどんどん増えていくので場合ごとに子Reducerを作成して親Reducerでまとめるのが良いみたいです。

```React:reducers/index.js
import { combineReducers } from 'redux';
import text from './textreducer';

const reducer = combineReducers({
  text,
});

export default reducer;

```

```React:reducers/textreducer.js
import {SEND_TEXT} from '../actions/index'

const initialAppState = {
  text: '',
};

const textreducer = (state = initialAppState, action) => {
  if (action.type === SEND_TEXT) {
    return Object.assign({}, state, {
      text: action.text
    });
  } else {
    return state;
  }
};

export default textreducer;

```

コンポーネントを修正します。
`mapDispatchToProps` でstateを更新、`mapStateToProps` でstateを取得しています。

```React:FirstPage.js
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import * as actions from '../actions';

class FirstPage extends Component {

  constructor(props){
    super(props);
    this.state = {
      text: '',
    }

    this.handleChange = this.handleChange.bind(this)
    this.handleClick = this.handleClick.bind(this)
  }

  handleChange(e){
    this.setState({
      text: e.target.value
    })
  }

  handleClick(){
    this.props.onClick(this.state.text);
    this.props.history.push("/secondpage");
  }

  render() {
    return (
      <div>
        最初のページ
        <br/>
        <input type='text' value={this.state.text} onChange={this.handleChange}></input>
        <p>{this.state.text}</p>
        <button onClick={this.handleClick}>画面遷移します</button>
      </div>
    );
  }
}

const mapStateToProps = (state) => ({
  text: state.text.text,
});

function mapDispatchToProps(dispatch) {
  return {
    onClick(text){
      dispatch(actions.inputText(text));
    }
  };
}

export default connect(mapStateToProps, mapDispatchToProps )(withRouter(FirstPage));

```

```React:SecondPage.js
import React, { Component } from 'react';
import { connect } from 'react-redux';

class SecondPage extends Component {
  render() {
    return (
      <div>
        <p>画面遷移先のページ</p>
        <p>{this.props.text}</p>
      </div>
    );
  }
}

const mapStateToProps = (state) => ({
  text: state.text.text,
});

export default connect(mapStateToProps)(SecondPage);

```

<img width="902" alt="スクリーンショット 2019-06-17 12.26.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439548/b8adf5e0-3de7-4e21-47fd-f49e6a427d8b.png">

<img width="865" alt="スクリーンショット 2019-06-17 12.26.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/439548/2191adec-9607-1a26-9862-1c78b4afc5e2.png">


最初に少し手間がかかりますが、Reduxを使うことに抵抗がなければこちらのほうがstateが管理しやすいので後々楽だと思います。