Redux
インストール
npm install redux react-redux
語句
- State: 値
- Reducer: Storeに保管されたStateを変更するもの
- Store: StateとReducerを持っているもの
- Provider: Storeを他のコンポーネントに渡すもの
使い方
Reducerの作成
- Reducer=新しいStateを返す関数。
- action.typeでどのような処理をするかが決まる。
- Stateが配列の場合、Stateをコピーした配列を操作してからreturnする。
State配列自体をreturnすると「変更なし」と判断され値が更新されない。
(同じ配列アドレスがreturnされるため)
const reducer = (state=初期値 , action) => {
switch (action.type) {
case 'タイプ1' :
return 新しいstate;
case 'タイプ2' :
return 新しいstate;
default :
return state;
}
};
Storeの作成
const store = createStore(reducer);
※ createStore
はdeprecated
となっているがここではそのまま使う
Providerの記述
import {Provider} from "react-redux";
としてProviderタグで囲む<Provider store={store}> <Hello/> </Provider>
Storeを使うコンポーネント
connect(関数)(コンポーネント)
で必要なStateをpropsに組み込む。props.dispatch()
でReducerを実行する。
カウンタのサンプル
import {createStore} from "redux";
import {Provider} from "react-redux";
import Hello from "./Hello"
const App = () => {
const reducer = (state=0 , action) => {
switch (action.type) {
case 'INCREMENT' :
return state + 1;
case 'DECREMENT' :
return state - 1;
}
};
const store = createStore(reducer);
return (
<Provider store={store}>
<Hello/>
</Provider>
);
};
export default App;
import { connect } from 'react-redux';
const Hello = (props) => {
const handeleButtonClick = () => {
props.dispatch({type: 'INCREMENT'});
};
return (
<p>{props.count}<button onClick={handeleButtonClick}>dispatch</button></p>
);
};
const mapStateToProps = state => {
return {count: state};
}
export default connect(mapStateToProps)(Hello);
メモ帳アプリのサンプル
npx create-react-app memo_app
cd memo_app
npm install redux react-redux
mkdir src/components
touch store.js
touch src/components/{Memo,AddForm,DelForm}.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {Provider} from "react-redux";
import store from "./store"
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store={store}>
<App/>
</Provider>
</React.StrictMode>
);
import {createStore} from "redux";
const addMemo = (state, action) => {
// 配列コピー
const newData = state.slice();
newData.unshift({message: action.message, created: new Date()});
return newData;
}
const deleteMemo = (state, action) => {
const newData = state.slice();
newData.splice(action.index, 1);
return newData;
}
const memoReducer = (state= [] , action) => {
switch (action.type) {
case 'ADD' :
return addMemo(state, action);
case 'DELETE' :
return deleteMemo(state, action);
default :
return state;
}
};
export const creteAddMemoAction = (message) => {
return {
type: 'ADD',
message: message
}
};
export const createDeleteMemoAction = (index) => {
return {
type: 'DELETE',
index: index
}
};
export default createStore(memoReducer);
import Memo from "./components/Memo";
import AddForm from "./components/AddForm";
import DelForm from "./components/DelForm";
const App = () => {
return (
<>
<AddForm/>
<DelForm/>
<Memo/>
</>
);
};
export default App;
import { connect } from 'react-redux'
import { useState } from "react";
import {creteAddMemoAction} from "../store"
const AddForm = (props) => {
const [message, setMessage] = useState('');
const handleButtonClick = () => {
props.dispatch(creteAddMemoAction(message));
setMessage('');
};
return (
<>
<input type="text" value={message} onChange={e=>setMessage(e.target.value)}/>
<button onClick={handleButtonClick}>addMemo</button>
</>
);
};
export default connect()(AddForm);
import { connect } from 'react-redux'
const Memo = (props) => {
return (
<ul>
{props.memos.map((memo, index) => <li key={index}>{memo.message}: {memo.created.toLocaleString()}</li>)}
</ul>
);
};
const mapStateToProps = state => {
return {memos: state};
}
export default connect(mapStateToProps)(Memo);
import { connect } from 'react-redux'
import { useState } from "react";
import {createDeleteMemoAction} from "../store"
const DelForm = (props) => {
const [index, setIndex] = useState(-1);
const handleButtonClick = () => {
if (index === -1) {
return;
}
props.dispatch(createDeleteMemoAction(index));
setIndex(-1);
};
return (
<>
<select onChange={e=>setIndex(Number(e.target.value))} value={index}>
{[<option key="-1" value="-1"></option>, props.memos.map((memo, index)=><option key={index} value={index}>{memo.message}</option>)]}
</select>
<button onClick={handleButtonClick}>delMemo</button>
</>
);
};
const mapStateToProps = state => {
return {memos: state};
}
export default connect(mapStateToProps)(DelForm);
コメント