React+Reduxでクイズアプリを作った。
クイズメーカー
##Redux
グローバルステートを管理するためのライブラリ。
グローバルステートは複数のページで同じ状態を共有するのに用いる。
逆に1つのページだけで用いる状態をローカルステートという。
##Action
グローバルステートの更新内容をまとめたオブジェクト。typeとpayloadのプロパティを持つ。
アクションを返す関数をアクションクリエータという。
actions/message.ts
const setMessage = (message: string) => {
return {
type: "SET_MESSAGE",
payload: {
message: message
}
}
}
##Reducer
グローバルステートとアクションを受け取り、アクションをもとにを更新したグローバルステートを返す関数のこと。
受け取ったグローバルステート自体を書き換えてはいけない。
リデューサーを複数使う場合はcombineReducersメソッドでまとめる。
reducers/index.ts
import { combineReducers } from "redux";
import { messageReducer } from "./message";
export const rootReducer = combineReducers({messageReducer: messageReducer});
export type RootState = ReturnType<typeof rootReducer>;
reducers/message.ts
import { AnyAction } from "redux";
type State = {
message: string
}
const messageReducer = (state: State = {message: ""}, action: AnyAction) => {
switch (action.type) {
case "SET_MESSAGE":
return {...state, message: action.payload.message}
default:
return state;
}
}
##Store
グローバルステートを保持するオブジェクト。
1つのアプリはストアは1つだけ持つ。
store/index.ts
import { createStore } from "redux";
import { rootReducer } from "../reducers";
export const store = createStore(rootReducer);
##Provider
各コンポーネントがグローバルステートを参照できるようにする。
App.tsx
import { Provider } from "react-redux";
import { BrowserRouter as Router, Route } from "react-router-dom";
import Header from "./components/commons/Header";
import IndexPage from "./components/pages/Index";
import { store } from "./store";
const App: React.FC = () => {
return (
<Provider store={store}>
<Router>
<Header />
<Route exact path="/" component={IndexPage} />
</Router>
</Provider>
);
}
export default App;
##グローバルステートの取得・更新
useSelectorメソッドでグローバルステートを取得。
アクションを引数としてdispatchメソッドを実行することでグローバルステートが更新される。
pages/Index.tsx
import { useSelector, useDispatch } from "react-redux";
import { RootState } from "./../../reducers";
const message = useSelector((state: RootState) => state.messageReducer.message);
const dispatch = useDispatch()
/* この場合はアクションクリエイターの返り値がアクション */
const onClick = () => dispatch(setMessage("Hello"));
/* connect()・mapStateToProps()を使わないのでprops不要 */
const IndexPage: React.FC = () => {}
export default IndexPage;