Reactを触ってみた
Reactを触ってみました
はじめに
zypressen.hatenablog.com
前回の記事で作ったAPIを使用して、以下のようなデータを表示したりするWebページをReactで作ってみたいと思います。
Webページの作成
Node version
$ node --version
v8.12.0
npm version
$ npm --version
6.4.1
yarn version
$ yarn --version
1.5.1
フォルダ構成
Reactのアプリを作成
以下ドキュメントに書いてある通りCreate React Appで作っていきます
https://reactjs.org/docs/create-a-new-react-app.html#create-react-app
以下のコマンドでReactのアプリを作ってくれます。
$ npx create-react-app react-demo
axiosの追加
今回はAPIにリクエストを送るのにaxiosというライブラリを使いたいと思います。
GitHub - axios/axios: Promise based HTTP client for the browser and node.js
以下のコマンドで追加します。
$ cd react-demo
$ yarn add axios
以下が最終的なpackage.jsonです。
{ "name": "react-demo", "version": "0.1.0", "private": true, "dependencies": { "axios": "^0.18.0", "react": "^16.5.2", "react-dom": "^16.5.2", "react-scripts": "1.1.5" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" } }
Component
ReactはいくつかComponentを組み合わせてページを作っていきます。
今回つくるページのComponentは以下のようにしてみました。
Context
続いて今回はContextを使ってみました。
Context – React
データをほかのComponentに受け渡すときは、propsを使い「親→子→孫」のようにバケツリレーを行っていましたが、Contextを使うことによってどのComponentからも参照できるようになります。
以下のようにContextを作ります。
import { createContext } from 'react'; const PersonContext = createContext(); export default PersonContext;
App.js
create-react-appで作った場合、すでにApp.jsがあると思います。
このファイルを以下のように変更していきます。
import React, { Component } from 'react'; import './App.css'; import axios from 'axios'; import PersonContent from './components/PersonContent'; import PersonContext from './context/Person'; class App extends Component { constructor(props) { super(props); this.state = { personList: [], // APIにリクエストを送って取得したPersonのリストを保持 } } componentDidMount() { this.getPersonList(); // 初期表示をする } getPersonList() { axios .get("http://localhost:8080/person") // URLを指定して .then(response => { // 成功したら const data = response.data; this.setState({ // stateに取得したデータをセット personList: data }) }) .catch(error =>{ // Errorが起きたら console.log(error); }) } render() { return ( <div className="App"> <PersonContext.Provider value={{ personList: this.state.personList, getPersonList: () => this.getPersonList() }}> <PersonContent /> </PersonContext.Provider> </div> ); } } export default App;
getPersonList()でaxiosを使ってAPIにリクエストを送り、返ってきたデータをstateにセットしています。
renderのところで表示するComponentなどを書いていきます。
ここで他のComponentでデータを参照できるようにContextを使っています。
PersonContext.Providerのvalueでデータを指定します。
今回はpersonListとgetPersonList()を指定しています。
PersonContent,js
なにかと書いてありますが、PersonRegisterとPersonListの2つのComponentで構成しています。
import React, { Fragment } from 'react'; import PersonRegister from './PersonRegister'; import PersonList from './PersonList'; import PersonContext from '../context/Person' const PersonContent = () => ( <PersonContext.Consumer> {({getPersonList}) => ( <Fragment> <PersonRegister getPersonList={getPersonList} /> <PersonList /> </Fragment> )} </PersonContext.Consumer> ); export default PersonContent;
とりあえずPersonListを見ていきます。
PersonList.js
このComponentはPersonのリストを表示します。
PersonContext.ConsumerでApp.jsのPersonContext.Providerのvalueで設定した値が使えます。
import React from 'react'; import PersonContext from '../context/Person'; const PersonList = () => ( <PersonContext.Consumer> {({personList}) => ( // PersonContext.Providerで設定した値 <div> <table> <thead> <tr> <th>name</th> <th>age</th> </tr> </thead> <tbody> {personList.map(person => ( <tr key={person.id}> <td>{person.name}</td> <td>{person.age}</td> </tr> ))} </tbody> </table> </div> )} </PersonContext.Consumer> ); export default PersonList;
PersonRegister.js
PersonContentに戻ります。
PersonRegisterのrender()以外でgetPersonList()を使いたかったので、propsで渡しています。
PersonList同様、PersonContext.ConsumerでgetPersonList()を使えるようにしています。
const PersonContent = () => ( <PersonContext.Consumer> {({getPersonList}) => ( // PersonContext.Providerで設定した値 <Fragment> <PersonRegister getPersonList={getPersonList} /> <PersonList /> </Fragment> )} </PersonContext.Consumer> );
続いて、データを登録するComponentです。
テキストボックスに値を入れるとstateに値をセットするようにしています。
送信ボタンを押すとAPIにPOSTリクエストを送ってデータを保存します。
送信後テキストボックスの値をクリアするために、formにrefを設定してリクエストを送った後にreset()を呼んでいます。
import React, { Component } from 'react'; import axios from 'axios'; class PersonRegister extends Component { constructor(props){ super(props); this.form = React.createRef(); // ref create this.state = { name: "", // フォームのnameの値 age: "" // フォームのageの値 } } handleChange(event) { this.setState({ [event.target.name]: event.target.value }) } handleSubmit(event) { event.preventDefault(); // 伝播を止める const data = {name: this.state.name, age: this.state.age}; axios .post("http://localhost:8080/person", data) .then(response => { this.props.getPersonList(); // リストを更新する this.form.current.reset(); // フォームをリセットする }) .catch(error => { console.log("error: ", error) }); } render() { return ( <div className="PersonRegister"> <form onSubmit={e => this.handleSubmit(e)} ref={this.form}> <label htmlFor="name">name</label> <input id="name" name="name" type="text" onChange={e => this.handleChange(e)} /> <label htmlFor="content">age</label> <input id="age" name="age" type="text" onChange={e => this.handleChange(e)} /> <button type="submit">submit</button> </form> </div> ); } } export default PersonRegister;
実行してみる
前回の記事で作ったAPIを起動しておきます。
以下コマンドを実行するとブラウザが開きます。
$ yarn start
自動で開かない場合は以下URLにアクセスしてみてください。
http://localhost:3000
実はこのままアクセスしてもListが表示されず、データの登録ができないです。
chromeなどのDeveloper toolsのconsoleを見ると、以下のようなエラーが出ていると思います。
Failed to load http://localhost:8080/person: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
前回作ったAPIのほうで、Access-Control-Allow-Originの設定をしていないため、ブラウザにより通信を拒否されてしまいます。
CORS対応
ということで前回作ったAPIのほうの修正をします。
以下のURLを参考にクラスを1つ追加して設定していきます。
https://docs.spring.io/spring-framework/docs/5.1.0.RELEASE/spring-framework-reference/web-reactive.html#webflux-cors-global
package com.example.demo; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.reactive.CorsWebFilter; import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource; import org.springframework.web.reactive.config.EnableWebFlux; import org.springframework.web.reactive.config.WebFluxConfigurer; @Configuration @EnableWebFlux public class WebConfig implements WebFluxConfigurer { @Bean public CorsWebFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); // cookie config.addAllowedOrigin("*"); // domain config.addAllowedHeader("*"); // header config.addAllowedMethod("*"); // http method UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return new CorsWebFilter(source); } }
APIを再起動して、ブラウザを更新するとListが表示され、データを登録もできると思います。
さいごに
githubのリポジトリです。
今後の記事に、このリポジトリを使いたいのでv1.0
というTagをうっておきました。
github.com
WebFluxのほうはv2.0
というTagをうっておきました。
github.com