React初心者向けの記事です。
コンポーネント間での値の受け渡しについて試行錯誤したものをまとめました。
まず最初のページと画面遷移先のページを用意します。
画面遷移はreact-router-dom
を使用して行います。
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)
import React, { Component } from 'react';
export default class SecondPage extends Component {
render() {
return (
<div>
<p>画面遷移先のページ</p>
</div>
);
}
}
ボタンを押したら画面遷移するというだけのシンプルなものです。
ルーティングはこんな感じ。
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>
);
}
}
それではコンポーネント間での値の受け渡しについて考えていきましょう。
最初のページにテキストボックスを用意します。
このテキストボックスに入力された値を画面遷移先に渡します。
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
で使用できます。
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)
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を作ります。
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を書きます。
export const SEND_TEXT = 'SEND_TEXT';
export const inputText = (text) => ({
type: SEND_TEXT,
text,
})
そしてReducer。Reducerは実装していくうちにどんどん増えていくので場合ごとに子Reducerを作成して親Reducerでまとめるのが良いみたいです。
import { combineReducers } from 'redux';
import text from './textreducer';
const reducer = combineReducers({
text,
});
export default reducer;
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を取得しています。
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));
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);
最初に少し手間がかかりますが、Reduxを使うことに抵抗がなければこちらのほうがstateが管理しやすいので後々楽だと思います。