| ページ一覧 | ブログ | twitter |  書式 | 書式(表) |

MyMemoWiki

差分

ナビゲーションに移動 検索に移動
1,766 バイト追加 、 2020年2月15日 (土) 08:05
編集の要約なし
==React==
[[Node.js]]
{{amazon|4873117887}}
#[http://typea.info/blg/glob/2017/08/react-react-router-redux-saga.html React の単純なサンプルに React Router を組み込んだものに Redux-Saga を適用する]
#[http://typea.info/blg/glob/2017/08/react-react-router-redux-saga-ajax.html React の単純なサンプルに React Router を組み込んだものに Redux-Saga を適用したものからAjax通信を組み込む]
#[http://typea.info/blg/glob/2017/08/react-react-router-redux-saga-superagent-bootstrap.html React環境->>React Router->>Redux-Saga->>SuperAgent に Bootstrapを適用する]
==導入==
*Reactはバックエンドロジックやデータベースを持たないが、使いたいものを使えばよい。
*Babelやwebpackのようなビルドツールも設定なしに利用できる。
PS C:\workspaces\vscode\reactlesson> > create-react-app react-lesson
Creating a new React app in C:\workspaces\vscode\reactlesson\react-lesson.
:
*アプリケーションが作成されたら実行
PS C:\workspaces\vscode\reactlesson> > cd react-lesson PS C:\workspaces\vscode\reactlesson> > npm start
*実行された
[[File:1086_react01.jpg]]
import './App.css';
const element = (<&lt;h1>&gt;Hello,world<&lt;/h1>&gt;);
class App extends Component {
render() {
==クイックスタート==
===JSX===
const element = <&lt;h1>&gt;Hello,world!<&lt;/h1>&gt;;
*文字列でも、HTMLでもなく、JSX
*JavaScriptの拡張文法
===JSX表現===
*どのようなJavaScriptの表現も、中括弧で囲むことでJSXに埋め込むことができる
*const element = (<&lt;h1>&gt;Hello, {formatName(user)}!<&lt;/h1>&gt;);
<&lt;!DOCTYPE html>&gt; <&lt;html>&gt; <&lt;head>&gt; <&lt;meta charset="UTF-8" />&gt; <&lt;title>&gt;Hello World<&lt;/title>&gt; <&lt;script src="https://unpkg.com/react@latest/dist/react.js"><&gt;&lt;/script>&gt; <&lt;script src="https://unpkg.com/react-dom@latest/dist/react-dom.js"><&gt;&lt;/script>&gt; <&lt;script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"><&gt;&lt;/script>&gt; <&lt;/head>&gt; <&lt;body>&gt; <&lt;div id="root"><&gt;&lt;/div>&gt; <&lt;script type="text/babel">&gt;
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {firstName:'Hiroto', lastName:'Yagi'};
const element = (<&lt;h1>&gt;Hello, {formatName(user)}!<&lt;/h1>&gt;);
ReactDOM.render(
element,
document.getElementById('root')
);
<&lt;/script>&gt; <&lt;/body>&gt; <&lt;/html>&gt;
*コンパイルされたJSXは通常のJavaScriptオブジェクト
function greeting(user) {
var now = new Date();
if (5 <&lt;= now.getHours() && now.getHours() <&lt;= 12) { return <&lt;h1> &gt; Good morning {user.firstName + ' ' + user.lastName}.<&lt;/h1>&gt;;
} else {
return <&lt;h1> &gt; Hello {user.firstName + ' ' + user.lastName}.<&lt;/h1>&gt;;
}
}
====属性に利用====
*中括弧を利用して、二重引用符なし(使用すると文字列リテラルとして扱われる)で直接利用できる。
<&lt;div id="root"><&gt;&lt;/div>&gt; <&lt;script type="text/babel">&gt;
function greeting(user) {
var now = new Date();
if (5 <&lt;= now.getHours() && now.getHours() <&lt;= 12) { return <&lt;h1> &gt; Good morning <&lt;a href={user.webpageUrl}>&gt;{user.firstName + ' ' + user.lastName}<&lt;/a>&gt;.<&lt;/h1>&gt;;
} else {
return <&lt;h1> &gt; Hello <&lt;a href={user.webpageUrl}>&gt;{user.firstName + ' ' + user.lastName}<&lt;/a>&gt;.<&lt;/h1>&gt;;
}
}
const user = {firstName:'Hiroto', lastName:'Yagi', webpageUrl:'http://typea.info'};
const element = (<&lt;h1>&gt;{greeting(user)}<&lt;/h1>&gt;);
ReactDOM.render(
element,
[[File:1089_react04.jpg]]
====子要素====
*子要素がない場合、XML同様 /> &gt; で閉じる
*子要素を含む
*JSXはHTMLよりJavaScriptにより近い。ReactDOMはキャメルケースプロパティ(HTMLでは、class がclassName、HTMLではtabindexがtabIndexなど)を持つ
function greeting(user) {
return <&lt;div>&gt; <&lt;h1> &gt; Good morning {user.firstName + ' ' + user.lastName}.<&lt;/h1>&gt; <&lt;h2><&gt;&lt;a href={user.webpageUrl}>&gt;webpage<&lt;/a><&gt;&lt;/h2>&gt; <&lt;/div>&gt;
;
}
*XSS攻撃の予防を助ける
function greeting(user, title) {
return <&lt;div>&gt; <&lt;h1>&gt;{title}<&lt;/h1>&gt; <&lt;h2> &gt; Good morning {user.firstName + ' ' + user.lastName}.<&lt;/h2>&gt; <&lt;h2><&gt;&lt;a href={user.webpageUrl}>&gt;webpage<&lt;/a><&gt;&lt;/h2>&gt; <&lt;/div>&gt;
;
}
const title = "<&lt;input type='button'>&gt;";
const user = {firstName:'Hiroto', lastName:'Yagi', webpageUrl:'http://typea.info'};
const element = (greeting(user,title));
*Babelは、React.createElement()を呼び出しコンパイルを行う
*以下の2つは同じ意味
const element1 = (<&lt;h1 className='greeting'>&gt;hello<&lt;/h1>&gt;);
const element2 = React.createElement('h1',{className:'greeting'},'hello');
*React.createElement()は、バグを防ぐ手助けをするが、本質的には以下のようなオブジェクトを生成する
*HTMLどこかに記述する、以下のDIV要素をroot DOM ノードと呼ぶ
*React DOM が管理するすべてが、この要素の中にある
<&lt;div id="root"><&gt;&lt;/div>&gt;
====React要素の更新====
*React要素は不変。一旦生成したら、子要素、属性などは変更できない。
*UIを更新するには、新しい要素を作成し、ReactDOM.rendar()に引き渡す。
function tick() {
const element = (<&lt;div>&gt;{(new Date()).toLocaleTimeString()}<&lt;/div>&gt;);
ReactDOM.render(
element,
setInterval(tick,1000);
[[File:1092_react07.jpg]]
<&lt;blockquote>&gt;通常のReact アプリケーションでは、ReactDOM.rendar()は 一度しか呼びださない。<&lt;/blockquote>&gt;
====Reactは必要なもののみ更新する====
*React DOMは、要素および子要素を前の状態と比較し、DOMの更新が必要な個所にのみ適用する。
*ブラウザツールで、上記のソースコードを確認する
[[File:1093_react08.jpg]]
<&lt;blockquote>&gt;毎tick()の呼び出しで、すべてのUIツリーを生成するよう記述してるが、変更が発生したテキストノードのみReact DOMにより更新されている。<&lt;/blockquote>&gt;
===コンポーネントと Props===
*コンポーネントはUIを独立し再利用可能な部分に分割する。
*このようなコンポーネントを"functional"と呼ぶ。
function Welcome(props) {
return <&lt;h1>&gt;Hello,{props.name}<&lt;/h1>&gt;;
}
*ES6のクラスをコンポーネントの定義として利用できる
class Welcome extends React.Component {
render() {
return <&lt;h1>&gt;Hello,{props.name}<&lt;/h1>&gt;;
}
}
*Elementは、ユーザー定義コンポーネントも表すことができる
function Welcome(props) {
return <&lt;h1>&gt;Hello,{props.name}<&lt;/h1>&gt;;
}
const element = <&lt;Welcome name='Hiroto' />&gt;
ReactDOM.render(
element,
*Reactがユーザー定義コンポーネントを表示するときに、JSXの属性からコンポーネントへ"props"としてオブジェクトが渡される。
<&lt;blockquote>&gt;コンポーネント名はいつも大文字から始める。DOM タグは、<&lt;div /> &gt; だが、<&lt;Welcome /> &gt; はコンポーネントを表現する。Welcomeがスコープに存在すること。<&lt;/blockquote>&gt;
====コンポーネントの構成====
*コンポーネントはその出力において、他のコンポーネントに影響を与えることができる
*Reactでこれらは、一般にコンポーネントで表現される
function Welcome(props) {
return <&lt;h1>&gt;Hello,{props.name}<&lt;/h1>&gt;;
}
function App() {
return ( <&lt;div>&gt; <&lt;Welcome name="Yagi"/>&gt; <&lt;Welcome name="Kaela"/>&gt; <&lt;Welcome name="Hiroto"/>&gt; <&lt;/div> &gt; );
}
ReactDOM.render(
<&lt;App />&gt;,
document.getElementById('root')
);
*一般的に新しいReactアプリケーションは、一つのAppコンポーネントを最上位に持つ。既存のアプリケーションにReactを統合する場合は、小さなコンポーネント、例えばButtonなど、ボトムアップから開始し、徐々にView階層の最上位にいたる。
<&lt;blockquote>&gt;コンポーネントは、一つのroot要素を返さなければならない。上記で、Welcome要素を div に含めたのはこのため<&lt;/blockquote>&gt;
====Propsは読み取り専用====
**Reactはかなりフレキシブルだが、1つ厳格なルールがある。function だろうと class だろうとコンポーネントはpropsを編集できない。
function Clock(props) {
return (
<&lt;div>&gt; <&lt;h2>&gt;{props.date.toLocaleTimeString()}<&lt;/h2>&gt; <&lt;/div>&gt;
);
}
function tick() {
ReactDOM.render(
<&lt;Clock date={new Date()} />&gt;,
document.getElementById('root')
);
render() {
return (
<&lt;div>&gt; <&lt;h2>&gt;{this.props.date.toLocaleTimeString()}<&lt;/h2>&gt; <&lt;/div>&gt;
);
}
#render()メソッドの中の、this.props.date を this.state.date に変更
#クラスにコンストラクタを追加し、this.stateの初期状態を記述する
#<&lt;Clock date={new Date()} /> &gt; から dateを削除
class Clock extends React.Component {
constructor(props) {
render() {
return (
<&lt;div>&gt; <&lt;h2>&gt;{this.state.date.toLocaleTimeString()}<&lt;/h2>&gt; <&lt;/div>&gt;
);
}
componentDidMount() {
this.timerID = setInterval(
() => &gt; this.tick(),1000
);
}
render() {
return (
<&lt;div>&gt; <&lt;h2>&gt;{this.state.date.toLocaleTimeString()}<&lt;/h2>&gt; <&lt;/div>&gt;
);
}
}
ReactDOM.render(
<&lt;Clock />&gt;,
document.getElementById('root')
);
// 正しい
this.setSatate({comment:'Hello'});
<&lt;blockquote>&gt;this.stateを割り当てることができるのは、コンストラクタのみ<&lt;/blockquote>&gt;
=====stateは、非同期に更新される=====
*Reactは、複数のsetState() をパフォーマンスのためにまとめて一度に処理する。
*関数は、ひとつ前の状態(state)を最初の引数として、更新時のpropsを2つ目の引数として取る
// 正しい
this.setState((prevState, props) => &gt; ({
counter: prevState.counter + prpos.increament
}));
*これらを別のsetState() で更新
componentDidMount() {
fetchPosts().then(response => &gt; { this.setState({ posts: response.posts }); }); fetchComments().then(response => &gt; { this.setState({ commentss: response.comments }); });
}
*マージはシャローなので、setState({comment}) は、this.state.posts を損なわずに、this.state.comments を置き換える
*状態はしばしばローカルから呼び出されるかカプセル化されていて、他からアクセスできない。
*コンポーネントは、自身の状態をpropsを通して子コンポーネントに渡す
<&lt;h2>&gt;It is {this.state.date.toLocalTimeString()}.<&lt;/h2>&gt;
*これは、ユーザー定義コンポーネントでも動作する
<&lt;FormattedDate date={this.state.date} />&gt;
*FormattedDateコンポーネントは、propsにdateを受け取り、Clockの状態が何かは知らない。
function FormatterDate(props) {
return <&lt;h2>&gt;It is {props.date.toLocaleTimeString()}.<&lt;/h2>&gt;;
}
*これは一般的に、トップダウン、もしくは、ユニディレクショナル データフローという
=====HTML=====
<&lt;button onclick="test()" />&gt;
=====React=====
<&lt;button onClick={test} />&gt;
*もう一つの違いは、Reactでは、falseを返しデフォルトのふるまいを防止することができない。
=====HTMLでデフォルトの新しいページを開くリンクのふるまいを防止する=====
<&lt;a href="#" onclick="console.log('hoge'); return false" >&gt;Click<&lt;/a>&gt;
=====React=====
function ActionLink() {
}
return (
<&lt;a href="#" onClick={handleClick} >&gt;Click<&lt;/a>&gt;
)
}
}
handleClick() {
this.setState(prevStae => &gt; ({
isToggleOn: !prevStae.isToggleOn
}));
render() {
return (
<&lt;button onClick={this.handleClick} >&gt;
{this.state.isToggleOn?"ON":"OFF"}
<&lt;/button>&gt;
);
}
}
ReactDOM.render(
<&lt;Toggle />&gt;,
document.getElementById('root')
);
*isLoggedIn により、異なるレンダリングがなされる。
function UserGreeting(props){
return <&lt;h1>&gt;Welcome to back!<&lt;/h1>&gt;
}
function GuestGreeting(props) {
return <&lt;h1>&gt;Please Sign up!<&lt;/h1>&gt;
}
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <&lt;UserGreeting />&gt;
} else {
return <&lt;GuestGreeting />&gt;
}
}
ReactDOM.render(
<&lt;Greeting isLoggedIn={true} />&gt;,
document.getElementById('root')
);
function LoginButton(props) {
return (
<&lt;button onClick={props.onClick} >&gt;
Login
<&lt;/button>&gt;
);
}
function LogoutButton(props) {
return (
<&lt;button onClick={props.onClick} >&gt;
Logout
<&lt;/button>&gt;
);
}
let button = null;
if (isLoggedIn) {
button = <&lt;LogoutButton onClick={this.handleLogoutClick} />&gt;
} else {
button = <&lt;LoginButton onClick={this.handleLoginClick} />&gt;
}
return (<&lt;div>&gt;{button}<&lt;/div>&gt;);
}
}
ReactDOM.render(
<&lt;LoginControl />&gt;,
document.getElementById('root')
);
const unreadMessages = props.unreadMessages;
return (
<&lt;div>&gt; <&lt;h1>&gt;Hello!<&lt;/h1>&gt; {unreadMessages.length > &gt; 0 && <&lt;h2>&gt;
You have {unreadMessages.length} unread messages.
<&lt;/h2>&gt;
}
<&lt;/div>&gt;
);
}
const messages = ['message1','message2'];
ReactDOM.render(
<&lt;MailBox unreadMessages={messages} />&gt;,
document.getElementById('root')
);
*条件 ? true : false
function UserGreeting(props){
return <&lt;h1>&gt;Welcome to back!<&lt;/h1>&gt;
}
function GuestGreeting(props) {
return <&lt;h1>&gt;Please Sign up!<&lt;/h1>&gt;
}
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
return (
<&lt;div>&gt;
{isLoggedIn ? (
<&lt;UserGreeting />&gt;
) : (
<&lt;GuestGreeting />&gt;
)
}
<&lt;/div>&gt;
);
}
ReactDOM.render(
<&lt;Greeting isLoggedIn={false} />&gt;,
document.getElementById('root')
);
}
return (
<&lt;div>&gt;Warning!<&lt;/div>&gt;
);
}
}
handleToggleClick() {
this.setState(prevState =>&gt;({showWarning : !prevState.showWarning}));
}
render() {
return (
<&lt;div>&gt; <&lt;WarningBanner warn={this.state.showWarning} />&gt; <&lt;button onClick={this.handleToggleClick}>&gt;
{this.state.showWarning ? 'Hide' : 'Show'}
<&lt;/button>&gt; <&lt;/div>&gt;
);
}
ReactDOM.render(
<&lt;Page />&gt;,
document.getElementById('root')
);
=====JavaScriptでリストの変換には、map()を利用する=====
const numbers = [1,2,3,4,5];
const doubled = numbers.map((number)=> &gt; number * 2);
console.log(doubled)
> &gt; [2, 4, 6, 8, 10]
*React では同様に配列をリストに変換する
====複数のコンポーネントをレンダリングする====
const fruits = ['apple','orange','grape','banana'];
const listItems = fruits.map((fruit) => <&gt; &lt;li>&gt;{fruit}<&lt;/li>&gt;);
ReactDOM.render(
<&lt;ol>&gt;{listItems}<&lt;/ol>&gt;,
document.getElementById('root')
);
function FruitList(props) {
const fruits = props.fruits;
const listItems = fruits.map((fruit) => <&gt; &lt;li key={fruit}>&gt;{fruit}<&lt;/li>&gt;);
return (
<&lt;ol>&gt;{listItems}<&lt;/ol> &gt;
);
}
const fruits = ['apple','orange','grape','banana'];
ReactDOM.render(
<&lt;FruitList fruits={fruits}/>&gt;,
document.getElementById('root')
);
*兄弟間で同じKeyを持つとエラーとなる
function ListItem(props) {
// この<&lt;li> &gt; にKeyを設定するのは、ここがルートになるため間違い return <&lt;li>&gt;{props.value}<&lt;/li>&gt;
}
function FruitList(props) {
const fruits = props.fruits;
// <&lt;ListItem>&gt;の配列となるため、ここでKeyを指定するのが正しい const listItems = fruits.map((fruit) => <&gt; &lt;ListItem key={fruit} value={fruit} />&gt;);
return (
<&lt;ol>&gt;{listItems}<&lt;/ol> &gt;
);
}
const fruits = ['apple','orange','grape','banana'];
ReactDOM.render(
<&lt;FruitList fruits={fruits}/>&gt;,
document.getElementById('root')
);
*中括弧のインラインにmap()を置くことができる
function ListItem(props) {
return <&lt;li>&gt;{props.value}<&lt;/li>&gt;
}
function FruitList(props) {
const fruits = props.fruits;
return (
<&lt;ol>&gt;{fruits.map((fruit) => <&gt; &lt;ListItem key={fruit} value={fruit} />&gt;)}<&lt;/ol> &gt;
);
const fruits = ['apple','orange','grape','banana'];
ReactDOM.render(
<&lt;FruitList fruits={fruits}/>&gt;,
document.getElementById('root')
);
render() {
return(
<&lt;form onSubmit={this.handleSubmit}>&gt; <&lt;label>&gt;Name: <&lt;input type="text" value={this.state.value} onChange={this.handleChange} /><&gt;&lt;/label>&gt; <&lt;input type="submit" value="Submit"/>&gt; <&lt;/form>&gt;
);
}
}
ReactDOM.render(
<&lt;NameForm />&gt;,
document.getElementById('root')
);
render(){
return(
<&lt;label>&gt;Select: <&lt;select value={this.state.value} onChange={this.handleChange}>&gt; <&lt;option value="grapefruit">&gt;Grape Fruit<&lt;/option>&gt; <&lt;option value="lime">&gt;Lime<&lt;/option>&gt; <&lt;option value="coconuts">&gt;Coconuts<&lt;/option>&gt; <&lt;option value="mango">&gt;Mango<&lt;/option>&gt; <&lt;/select>&gt; <&lt;/label>&gt;
);
}
render(){
return (
<&lt;label>&gt;Textarea:<&lt;textarea value={this.state.value} onChange={this.handleChange} /><&gt;&lt;/label>&gt;
);
}
}
ReactDOM.render(
<&lt;div>&gt; <&lt;SelectParts />&gt; <&lt;TextareaParts />&gt; <&lt;/div>&gt;,
document.getElementById('root')
);
render(){
return (
<&lt;form>&gt; <&lt;label>&gt;Is going:<&lt;input name="isGoing" type="checkbox" checked={this.state.isGoing} onChange={this.handleInputChange}/><&gt;&lt;/label>&gt; <&lt;br />&gt; <&lt;label>&gt;Number of guests:<&lt;input name="numberOfGuests" type="number" value={this.state.numberOfGuests} onChange={this.handleInputChange}/><&gt;&lt;/label>&gt; <&lt;/form>&gt;
);
}
}
ReactDOM.render(
<&lt;div>&gt; <&lt;Reservation />&gt; <&lt;/div>&gt;,
document.getElementById('root')
);
=====水が沸騰しているかどうかの計算を行う。=====
function BoilingVerdict(props) {
if (props.celsius >&gt;= 100) { return <&lt;p>&gt;The water would boil.<&lt;/p>&gt;;
}
return <&lt;p>&gt;The water would not boil.<&lt;/p>&gt;
}
class Calculator extends React.Component {
const temprature = this.state.temprature;
return (
<&lt;fieldset>&gt; <&lt;legend>&gt;Enter temprature in Celsius:<&lt;/legend>&gt; <&lt;input value={temprature} onChange={this.handleChange} />&gt; <&lt;BoilingVerdict celsius={parseFloat(temprature)} /> &gt; <&lt;/fieldset>&gt;
);
}
}
ReactDOM.render(
<&lt;div>&gt; <&lt;Calculator />&gt; <&lt;/div>&gt;,
document.getElementById('root')
);
};
function BoilingVerdict(props) {
if (props.celsius >&gt;= 100) { return <&lt;p>&gt;The water would boil.<&lt;/p>&gt;;
}
return <&lt;p>&gt;The water would not boil.<&lt;/p>&gt;
}
function toCelsius(fahrenheit) {
const scale = this.props.scale;
return (
<&lt;fieldset>&gt; <&lt;legend>&gt;Enter temprature in {scaleName[scale]}:<&lt;/legend>&gt; <&lt;input value={temprature} onChange={this.handleChange} />&gt; <&lt;BoilingVerdict celsius={parseFloat(temprature)} /> &gt; <&lt;/fieldset>&gt;
);
}
const fahrenheit = scale == 'c' ? tryConvert(temprature, toFahrenheit) : temprature;
return (
<&lt;div>&gt; <&lt;TempratureInput scale="c" temprature={celsius} onTempratureChange={this.handleCelsiumChange} />&gt; <&lt;TempratureInput scale="f" temprature={fahrenheit} onTempratureChange={this.handlFahrenheitChange}/>&gt; <&lt;BoilingVerdict celsius={parseFloat(celsius)} />&gt; <&lt;/div>&gt;
);
}
}
ReactDOM.render(
<&lt;div>&gt; <&lt;Calculator />&gt; <&lt;/div>&gt;,
document.getElementById('root')
);
*これは、特にサイドバーやダイアログなどボックスを表現するコンポーネント共通
*このようなコンポーネントには特別な子供propを使用し直接その要素に出力する
*<&lt;FancyBorder>&gt;の内側に何があっても、JSXタグはFancyBorderコンポーネントをprops.children として経由する <&lt;style type="text/css">&gt;
div.FancyBorder {
border : 2px dashed;
border-color: blue;
}
<&lt;/style>&gt;
function FancyBorder(props) {
return (
<&lt;div className={'FancyBorder FancyBorder-' + props.color}>&gt;
{props.children}
<&lt;/div>&gt;
);
}
function WelcomDialog() {
return (
<&lt;FancyBorder color="blue">&gt; <&lt;h1 className="Dialog-title">&gt;Welcome<&lt;/h1>&gt; <&lt;/FancyBorder>&gt;
);
}
ReactDOM.render(
<&lt;div>&gt; <&lt;WelcomDialog />&gt; <&lt;/div>&gt;,
document.getElementById('root')
);
function Dialog(props) {
return (
<&lt;FancyBorder color="blue">&gt; <&lt;h1 className="Dialog-title">&gt;{props.title}<&lt;/h1>&gt; <&lt;/FancyBorder>&gt;
);
}
function FancyBorder(props) {
return (
<&lt;div className={'FancyBorder FancyBorder-' + props.color}>&gt;
{props.children}
<&lt;/div>&gt;
);
}
function WelcomDialog() {
return (
<&lt;Dialog title="Welcome" />&gt;
);
}

案内メニュー