[[JSライブラリ]] > React.js * React.js [#y37ef538] #setlinebreak(on) #todo(Redux) #contents -- 参考 --- https://reactjs.org/docs/try-react.html --- https://reactjs.org/docs/add-react-to-a-new-app.html --- https://reactjs.org/docs/add-react-to-an-existing-app.html -- サンプル --- http://www.magata.net/test/react/ ** プロジェクトの作成とローカルサーバ起動 [#va1aa7c6] #html(<div style="padding-left:10px;">) https://reactjs.org/docs/add-react-to-a-new-app.html #myterm2(){{ npm install -g create-react-app create-react-app my-app cd my-app npm start }} ※http://localhost:3000/ でアクセス可能。 #html(</div>) ** ビルド [#g9dc70a8] #html(<div style="padding-left:10px;">) #myterm2(){{ npm run build }} ※build 配下に出力されるファイルをWeb公開ディレクトリに配置する。 &color(red){ただし、HTTPSアクセスでないと service-worker.js などの読み込みに失敗する。};(証明書が有効でない時も同じ) なので、プライベートCAで自己署名した場合などは、プライベートCAの証明書をブラウザにインポートする必要がある。 ※参考 ... [[Javaでhttps通信時の証明書検証について]]、[[ApacheでSSL(SNI)設定]] *** サブディレクトリ配下で公開する場合 [#c0bccb32] #html(<div style="padding-left:10px;">) package.json に以下を追記してからビルド #mycode2(){{ { . . "homepage": "/test/react/" } }} ※ http://xxx.xxx.xxx/test/react/ 配下で公開する場合 ルーティング定義時(BrowserRouter)は basename で指定する(後述) #myhtml2(){{ <BrowserRouter basename="/test/react"> <!-- サブディレクトリ配下で公開する場合 --> }} #html(</div>) *** CDNを利用する場合 [#o31ec96c] #html(<div style="padding-left:10px;">) React、ReactDOM は CDNも利用できるらしい。 ・・が、通信がクロスドメインになるので、scriptタグに crossorigin 属性付けろ、とか Access-Control-Allow-Origin: * ヘッダを付けろとか書いてる。 https://reactjs.org/docs/cdn-links.html #html(</div>) #html(</div>) ** レンダリング、JSXについて [#k51b6142] #html(<div style="padding-left:10px;">) *** 基本ルール [#t64ceeb1] #html(<div style="padding-left:10px;">) HTML要素はjs内にJSXで記載し変数として扱う事ができる。また、この変数は変数として扱う事ができる。 #myhtml2(){{ const element = <h1>Hello, world</h1>; ReactDOM.render( element, document.getElementById('root') ); }} テンプレートは関数 または コンポーネントとして定義する事ができる。 関数定義 #myhtml2(){{ function Welcome(props) { return <h1>Hello, {props.name}</h1>; } ReactDOM.render( <Welcome name="Test" />, document.getElementById('root') ); }} コンポーネント定義 #myhtml2(){{ class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } } ReactDOM.render( <Welcome name="Test" />, document.getElementById('root') ); }} JSXへの変数展開は { } で記述する。 #myhtml2(){{ <h1>Hello, {user.name}</h1> }} HTML要素は createElement する事もできる。 #mycode2(){{ const element = React.createElement( 'h1', {className: 'greeting'}, 'Hello, world!' ); // または const element = { type: 'h1', props: { className: 'greeting', children: 'Hello, world' } }; }} #html(</div>) *** CSSの記述 [#d8cd1654] #html(<div style="padding-left:10px;">) ハイフンは使用できない(キャメルケースで記載する) #mycode(){{ style={{marginRight: '10em'}} .. OK style="margin-right: 10em" .. NG }} #html(</div>) *** classの記述 [#e2542abb] #html(<div style="padding-left:10px;">) class は className と記載する。 #mycode2(){{ className="greeting" .. OK class="greeting" .. NG }} #html(</div>) *** リストの描画 [#me3ae983] #myhtml2(){{ function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => <li>{number}</li> ); return ( <ul>{listItems}</ul> ); } const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( <NumberList numbers={numbers} />, document.getElementById('root') ); }} #html(</div>) ** ページ切り替え [#id2f89a7] #html(<div style="padding-left:10px;">) 参考 : https://qiita.com/takanorip/items/649c7862a8a5380dd8be react-router-dom を使用する *** インストール [#q768b31b] #html(<div style="padding-left:10px;">) #myterm2(){{ npm install react-router --save-dev npm install react-router-dom --save-dev }} #html(</div>) *** ルーティング定義など [#k8b7b304] #html(<div style="padding-left:10px;">) App.js #myhtml2(){{ import React, { Component } from 'react'; import { BrowserRouter, Route, Link } from 'react-router-dom'; import Home from "./components/Home"; import Page1 from "./components/Page1"; import Page2 from "./components/Page2"; import './App.css'; class App extends Component { name = 'Test1'; render() { return ( <BrowserRouter basename="/test/react"> <!-- サブディレクトリ配下で公開する場合 --> <div className="App"> <div id="header"> ヘッダ </div> <ul id="header-menu"> <li><Link to="/">Home</Link></li> <li><Link to="/page1">Page1へ</Link></li> <li><Link to="/page2">Page2へ</Link></li> </ul> <div id="content"> <Route exact path="/" component={Home} /> <Route path="/page1" component={Page1} /> <Route path="/page2" component={Page2} /> </div> <div id="footer"> フッタ </div> </div> </BrowserRouter> ); } } export default App; }} #html(</div>) *** 使用例 [#v78c7fcb] #html(<div style="padding-left:10px;">) ・リンクによる切り替えは Link を使用する。 ・処理で遷移する場合は history を使用する。※withRouter を使用しつつ、メソッドを bind する事により history へのアクセスが可能になる。 ※react router v4 components/Home.js #myhtml2(){{ import React, { Component } from 'react'; import { Link } from 'react-router-dom'; import { withRouter } from 'react-router'; class Home extends Component { name = 'Home'; //constructor(props) { // super(props); // //this.movePage = this.movePage.bind(this) //} moveTop(e) { console.log("moveTop"); this.props.history.push('/'); } movePage(url,e) { console.log("movePage"); e.preventDefault(); this.props.history.push(url); } render() { return ( <div className="Home"> <h1>{this.name}!</h1> <br /> <div> <h3>イベントハンドラからページ切り替え</h3> <div style={{paddingLeft:'10px'}}> <button onClick={this.movePage.bind(this, '/')}>Topへ</button><br /> <button onClick={this.movePage.bind(this, '/page1')}>page1へ</button><br /> <button onClick={this.movePage.bind(this, '/page2')}>page2へ</button><br /> </div> </div> <br /> <div> <h3>Linkによるページ切り替え</h3> <ul style={{marginLeft: '10px', paddingLeft:'10px' }}> <li><Link to="/">Home</Link></li> <li><Link to="/page1">Page1へ</Link></li> <li><Link to="/page2">Page2へ</Link></li> </ul> </div> </div> ); } } export default withRouter(Home); }} #html(</div>) #html(</div>) ** イベント処理 [#r9b9f211] #html(<div style="padding-left:10px;">) https://reactjs.org/docs/handling-events.html *** 初期処理 [#jd694d88] #html(<div style="padding-left:10px;">) componentDidMount で初期処理を行う事ができる。 #mycode2(){{ class Page1 extends Component { componentWillMount() { // ここで初期処理を行う }; . . } }} #html(</div>) *** クリック時の処理など [#r4a04fe6] #html(<div style="padding-left:10px;">) 関数定義する場合 #myhtml2(){{ function ActionLink() { function handleClick(e) { e.preventDefault(); console.log('The link was clicked.'); } return ( <a href="#" onClick={handleClick}> Click me </a> ); } }} コンポーネント化する場合 #myhtml2(){{ class LoggingButton extends React.Component { handleClick = () => { console.log('this is:', this); } render() { return ( <button onClick={this.handleClick}> Click me </button> ); } } }} #html(</div>) #html(</div>) ** 非同期通信 [#ob0771a2] #html(<div style="padding-left:10px;">) 以下には jQuery などの好きなライブラリを使えと書いてある。React 組み込みのものは無い模様。 https://reactjs.org/docs/faq-ajax.html#how-can-i-make-an-ajax-call *** サンプル [#u0288ba5] #html(<div style="padding-left:10px;">) とりあえず参考URL の通り実装してみる。 #myhtml2(){{ import React, { Component } from 'react'; class Page1 extends Component { constructor(props) { super(props); this.state = { error: null, isLoaded: false, items: [] }; } componentDidMount(){ fetch("http://example.com/api/books/") .then(res => res.json()) .then( (result) => { this.setState({ isLoaded: true, items: result.items }); }, (error) => { this.setState({ isLoaded: true, error }); } ) } render() { const { error, isLoaded, items } = this.state; if (error) { return <div>Error: {error.message}</div>; } else if (!isLoaded) { return <div>Loading...</div>; } else { return ( <div className="Page1"> <h1>Page1!!</h1> <br /> <table> <thead> <tr> <th>No</th><th>Isbn</th><th>Title</th><th>Price</th><th>Date</th> </tr> </thead> <tbody> {items.map(item => ( <tr key={item.isbn}> <td>X</td><td>{item.isbn}</td><td>{item.title}</td><td>{item.price}</td><td>{item.date}</td> </tr> ))} </tbody> </table> </div> ); } } } export default Page1; }} #html(</div>) #html(</div>)