LoginSignup
124
102

More than 3 years have passed since last update.

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

Posted at

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

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

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)

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

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

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

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

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>
        );
    }
}

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

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

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)

案1 react-router-domの機能を使う

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

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

受け取った値は

this.props.location.state.text

で使用できます。

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)

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を使う場合は下記の2つのパッケージをインストールしましょう。
redux
react-redux

まずはstoreを作ります。

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を書きます。

action.js
export const SEND_TEXT = 'SEND_TEXT';

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

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

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

const reducer = combineReducers({
  text,
});

export default reducer;

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を取得しています。

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));

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);

スクリーンショット 2019-06-17 12.26.34.png

スクリーンショット 2019-06-17 12.26.43.png

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

124
102
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
124
102