おじさんが一生懸命勉強しているというだけなので、どうぞ他のページを見てください。すみません。
#そもそもjavascriptの理解
npm,package.jsonの理解
https://qiita.com/righteous/items/e5448cb2e7e11ab7d477
javascript再入門
https://developer.mozilla.org/ja/docs/Web/JavaScript/A_re-introduction_to_JavaScript
JavaScript では true && expression は必ず expression と評価され、false && expression は必ず false と評価される
{unreadMessages.length > 0 &&
<h2>
You have {unreadMessages.length} unread messages.
</h2>
}
condition ? true : false 演算子
{isLoggedIn ? 'currently' : 'not'}
react-redux
すべて
https://webbibouroku.com/Blog/Article/react-redux-todo
をやってみたもの。
##そもそもreactの理解
秀逸なチュートリアル
https://ja.reactjs.org/tutorial/tutorial.html
- promiseについて
Promiseは非同期処理を抽象化したオブジェクトとそれを操作する仕組みのことであり、非同期処理等を上手くパターン化できる。
非同期に対するオブジェクトとルールを仕様化して、 統一的なインターフェースで書く。具体的には非同期処理を抽象化したpromiseオブジェクトというものを用意し、 そのpromiseオブジェクトに対して成功時の処理と失敗時の処理の関数を登録する
function fetchURL(URL) {
return new Promise((resolve, reject) => {
const req = new XMLHttpRequest();
req.open("GET", URL, true);
req.onload = () => {
if (200 <= req.status && req.status < 300) {
resolve(req.responseText);
} else {
reject(new Error(req.statusText));
}
};
req.onerror = () => {
reject(new Error(req.statusText));
};
req.send();
});
}
- 被制御コンポーネント
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
実行例
const URL = "https://httpbin.org/get";
fetchURL(URL).then(function onFulfilled(value){
console.log(value);
}).catch(function onRejected(error){
console.error(error);
});
promiseオブジェクトには以下の3つの状態が存在します。
-
Fulfilled
resolve(成功)した時。このとき onFulfilled が呼ばれる -
Rejected
reject(失敗)した時。このとき onRejected が呼ばれる -
Pending
FulfilledまたはRejectedではない時。つまりpromiseオブジェクトが作成された初期状態等が該当する -
react componentのライフサイクル
https://qiita.com/kawachi/items/092bfc281f88e3a6e456 -
メモ:
this
が指し示す範囲は難しい -
Virtual DOMのメリット
-
HTMLとはツリー構造であり、2つのツリー構造のdiffを算出して、それをDOMにpatchするアクションを作り、常に最小のコストで状態遷移を表現する事がVirtual DOMという発想のスタート地点
-
Virtual DOM実装とは、仮想DOMの構造体表現+それを用いたdiff/patchアルゴリズム
-
render()メソッド
-
「Virtual DOM(仮想DOM)」でできたReactコンポーネントのツリーを最終的にブラウザで表示できる生DOMのツリーに変換する。
-
react-domのrender()メソッドの第一引数に「親コンポーネント(JSXの形で)」、第二引数に「実際にhtmlファイルで表示させる部分の要素」を渡す
-
イミュータビリティ(ミューテート:書き換え)
-
ミューテートを避ける事で、複雑な機能が簡単に実装できる(元に戻す)
-
データの変更検知ができる
-
再レンダータイミングが簡単にわかる
-
純関数
-
全ての React コンポーネントは、自己の props に対して純関数のように振る舞わねばならず、入力したpropsを変更してはいけない。
-
ライフサイクルメソッド
-
コンポーネントクラスで特別なメソッドを宣言することで、コンポーネントがマウント(DOMが描画)したりアンマウント(DOMが削除)したりした際にコードを実行することができる。
componentDidMount()
componentWillUnmount()
-
Functional Component
-
内部に状態を持たない
-
コンポーネントで使用したい値はpropsとして引数を通して受け取る
-
アローファンクション構文で書くとかなりシンプルに書ける
-
Class Component
- ES6のClass構文 -
パラメータprops(「プロパティ」の略)を受け取り、renderメソッドを介して表示するビューの階層を返す。renderメソッドは多くの場合JSXを使う
-
内部に状態を持つことができる。constructorメソッドを追加し
this.state
へ -
Class Componentで保持しているState(状態)の値は、それに紐づいている子コンポーネントからpropsを通して受け取る
-
Class Componentに子コンポーネントを紐づけるには、子コンポーネントを独自タグ(独自要素)にして親コンポーネントに挿入する。
-
挿入した子コンポーネント要素の中に「任意の名前」をつけた属性を設け、渡したい値を指定する。
-
ES6なら明示的な
super()
を呼び出す事が必須。クラスのコンポーネントは常に props を引数として親クラスのコンストラクタを呼び出す必要がある -
コンポーネントに付属しているpropTypesプロパティを使って、受け取るpropsの値を一つ一つの型のチェックや必須チェックなどを行なう
-
イベントハンドラは、JSX内にonClickのように「on○○○(キャメルケースで書く)」として設置
-
またコールバック関数として実行する際にちゃんと関数内の「this」が機能するように、constructor()内でthisをbindしておく必要がある。
-
stateは
setState()
を経由してのみ更新。直接代入してよいのはconsructorのみ
誤:this.state.comment = 'Hello';
正:this.setState({comment: 'Hello'});
- stateのフロー
- “トップダウン” もしくは “単一方向” データフローと呼ばれ、 state も必ず特定のコンポーネントが所有し、state から生ずる全てのデータまたは UI は、ツリーでそれらの “下” にいるコンポーネントにのみ影響する
- Key
- どの要素が変更、追加もしくは削除されたのかを React が識別する為、一意のKeyを設定する。
- 通常一意のアプリケーション側のKeyを設定することになる。最終手段として配列のindexを設定することもできるが、配列の順番が変わる可能性がある場合もあるので配列のindexをKeyとするのは非推奨。
- Keyは全体でuniqueである必要はなく複数の配列それぞれの中で一意であれば良い
- Listitemのli要素にKeyを設定しない。Listitem側に設定すること
##用語
ECMAScript
ECMAScript(エクマスクリプト)は、JavaScriptの標準であり、Ecma Internationalのもとで標準化手続きなどが行われている。
babel:ES6記法をES5に変換するトランスパイラ
babel言語定義 https://babeljs.io/docs/en/editors/
-
アロー関数:通常の function 式のより短く記述できる代替構文であることに加え、thisの指し示す範囲を宣言時に固定化する。
-
アロー不使用:<button className="square" onClick={function() { alert('click'); }}>
-
アロー使用:<button className="square" onClick={() => alert('click')}>
-
アロー関数を使うとコンストラクタでのバインドを省ける
https://qiita.com/mejileben/items/69e5facdb60781927929 -
redux-saga
-
タスクによる非同期処理を実現
-https://qiita.com/kuy/items/716affc808ebb3e1e8ac#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB -
fork
タスクをfork -
yield
非同期タスクの生成 -
take
非同期の処理待ち -
put
Actionをdispatchする -
call
Promiseの完了を待つ
// 追加
function* handleRequestSearchByLocation() {
while (true) {
const action = yield take(SUCCESS_USER);
const { payload, error } = yield call(API.searchByLocation, action.payload.location);
if (payload && !error) {
yield put(successSearchByLocation(payload));
} else {
yield put(failureSearchByLocation(error));
}
}
}
function* handleRequestUser() {
while (true) {
const action = yield take(REQUEST_USER);
const { payload, error } = yield call(API.user, action.payload);
if (payload && !error) {
yield put(successUser(payload));
} else {
yield put(failureUser(error));
}
}
}
export default function* rootSaga() {
yield fork(handleRequestUser);
yield fork(handleRequestSearchByLocation); // 追加
}
##react/reduxインストール
node.jsインストール 12.14.0 + npm
左の方をクリック、時間がかかるので注意
npm install -g create-react-app
C:\Users\piror>
npm install -g create-react-app
C:\Users\piror\AppData\Roaming\npm\create-react-app -> C:\Users\piror\AppData\Roaming\npm\node_modules\create-react-app\index.js
- create-react-app@3.3.0
added 91 packages from 45 contributors in 83.197s
C:\Users\piror>
create-react-app react-redux-todo
create-react-app react-redux-todo
C:\Users\piror>create-react-app react-redux-todo
Creating a new React app in C:\Users\piror\react-redux-todo.
Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts with cra-template...
~割愛~
npm run eject
Removes this tool and copies build dependencies, configuration files
and scripts into the app directory. If you do this, you can’t go back!
We suggest that you begin by typing:
cd react-redux-todo
npm start
Happy hacking!
C:\Users\piror>
cd react-redux-todo
npm install --save redux react-redux redux-logger
C:\Users\piror>cd react-redux-todo
C:\Users\piror\react-redux-todo>npm install --save redux react-redux redux-logger
npm WARN tsutils@3.17.1 requires a peer of typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta but none is installed. You must install peer dependencies yourself.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.11 (node_modules\jest-haste-map\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.11: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.11 (node_modules\chokidar\node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.11: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@2.1.2 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.1.2: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
+ redux@4.0.5
+ redux-logger@3.0.6
+ react-redux@7.1.3
added 6 packages from 31 contributors and audited 906399 packages in 736.353s
33 packages are looking for funding
run \`npm fund` for details
found 0 vulnerabilities
C:\Users\piror\react-redux-todo>
reduxについて
reactとともに使われるフレームワークだが、react専用というものでもない。FLUXが源流
3つの原則
-
Single source of truth (信頼できる一つの情報源)
-
State is read-only (状態は読み取り専用)
-
Changes are made with pure functions (変更は純粋な関数によって行われる)
-
要素
-
Action
{
type: ADD_TODO,
text: 'Build my first Redux app'
}
- Action Creator
function addTodo(text) {
return {
type: ADD_TODO,
text
}
}
- Store:applicationの状態を保持。決められた手法でしかアクセスさせない。
getstate()
dispatch(action)
subscribe(listener)
// storeを作成するコード
import { createStore } from 'redux'
import todoApp from './reducers'
const store = createStore(todoApp)
// stateを取得
console.log(store.getState())
// アクションをディスパッチ(stateを更新)
store.dispatch(addTodo('Learn about actions'))
-
State:アプリケーションの状態、Reduxでは大事なものとして集中・手続き管理する。
-
Reducer:ストアに送信されたアクションに応じて、アプリケーションの状態がどのように変化するかを指定する。アクションは何が起こったかを説明するだけであり、アプリケーションの状態がどのように変化するかを説明しないことに注意。
-
(previousState, action) => nextState
-
引数をミューテートしてはダメ。つまり別のコピー実体を作って渡す事
-
APIコールやトランザクションのルーティングなど副作用をもたらしてはダメ
-
Date.now()やMath.random()など、純関数以外のものをコールしてはダメ
-
reducerが大きくなり分割したい場合、combineReducersを使用
import {
ADD_TODO,
TOGGLE_TODO,
SET_VISIBILITY_FILTER,
VisibilityFilters
} from './actions'
...
function todoApp(state = initialState, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return Object.assign({}, state, {
visibilityFilter: action.filter
})
case ADD_TODO:
return Object.assign({}, state, {
todos: [
...state.todos,
{
text: action.text,
completed: false
}
]
})
default:
return state
}
}
プログラミング
フォルダ・ファイル作成
/src ディレクトリ以下にそれぞれのディレクトリを作成
actions
components
containers
reducers
actions/Todo.js, components/Todo.js, containers/Todo.js, reducers/Todo.js, createStore.js 各種ファイルをそれぞれ作成
jsの修正
割愛
実行
npm start
index.jsにてコンパイルエラー発生!
//これだめ import registerServiceWorker from './registerServiceWorker';
//これもだめ import registerServiceWorker from './serviceWorker';
import * as utils from './serviceWorker';
import { register } from './serviceWorker'; // これOK
TypeScriptの場合は default export は避けた方がよい (リファクタリングした場合もちゃんと検知できる等名前付きexportの方がメリットが大きい)
再度実行、その後各ファイルを更新しtodo機能を作成
解説
各ソースファイルの主要機能
-
index.js
-
ReactDOM.render
-
register();
-
App.js
-
class App extends Component
-
<div classname="App"> <Todo />
-
export default App
-
createStore.js
-
Store:状態を管理するグローバルで単一のオブジェクトを作成する処理
-
cobinereducers
-
reduxCreateStore( combineReducers({ todo: todoReducer, }),
applyMiddleware( logger, ) -
serviceWorker.js(初期ファイル、今回は呼ばれるだけ)
-
actions/Todo.js
Reducerにしてほしい処理を伝えるためのメッセージ。どういうアクションを行うか?というtype(必ず持つ)と、他の任意のパラメータを持ったプレーンなオブジェクト。
payloadプロパティは処理に使うパラメータ -
addTodo = (todo)
-
return( type: 'ADD_TODO',
-
payload: { todo: todo } )
-
components/Todo.js
-
補足: コンポーネント名は常に大文字で始めてください。
-
React は小文字で始まるコンポーネントを DOM タグとして扱います。例えば、<div /> は HTML の div タグを表しますが、 はコンポーネントを表しており、スコープ内に Welcome が存在する必要があります。
- export default class Todo extends React.Component
- render()
-
containers/Todo.js
コンポーネントとreduxによる状態管理を結びつける。 -
mapStateToProps = state =>return {todo: state.todo,
-
このコンポーネントで使用する state を切り出して、コンポーネント内のpropsで参照できるようにマッピングするための関数
-
mapDispatchToProps = dispatch =>return {addTodo: (todo) => dispatch(actions.addTodo(todo)),
-
dispatchするための関数をpropsにマッピングするための関数
-
export default connect(mapStateToProps, mapDispatchToProps)(Todo)
-
connect関数でコンポーネントに接続しexportすることで、コンポーネントがreduxによる状態管理を意識せず、stateやdispatchを参照、実行できるようになる。
-
reducers/Todo.js
。actionを元に状態遷移+定義したアクションをdispatchする
reducerは引数で現在の状態(state)とdispatchされたactionを受け取り、 actionに応じた状態のstateを返すことで状態を更新する。
state は書き換えるのではなく新たなオブジェクトとしなければならない。 -
export const todoReducer = (state = initialState, action) => {
-
switch (action.type) { case 'ADD_TODO':