- 追加された行はこの色です。
- 削除された行はこの色です。
- React.js へ行く。
[[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 組み込みのものは無い模様。
※ Promiseを返すものを使っていれば実装はそんなに変わらないと思う。
※ Promiseを返すものを使っていれば実装はそんなに変わらないと思うが、ラップはしておいた方が都合は良さそう。
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>)