依存関係のインストール:
npm install redux 反応-redux
src/store ディレクトリを作成し、createStore.js ファイルを作成します。
createStore.js ファイルを作成し、createStore メソッドをエクスポートします。
import { combineReducers } from 'redux'
import userReducer from './user.reducer'
export default combineReducers(userReducer)
ストア ディレクトリにリデューサーを保存するためのリデューサー フォルダーを作成します。
src/store/reducers/user.reducer.js
export const InitialState = {
email: '[email protected]',
name: 'huiquan',
avatar: 'https://api.realworld.io/images/demo-avatar.png',
loginStatus: 0
}
export default (state = InitialState, action) => {
switch (action.type) {
case 'modify-email':
return { ...state, email: action.payload }
case 'modify-name':
return { ...state, name: action.payload }
case 'modify-login-status':
return { ...state, loginStatus: action.payload }
case 'login':
return { ...state, ...action.payload, loginStatus: 1 }
default:
return state
}
}
rootReducer.jsを作成する
src/store/reducers/root.reducer.js combinReducers メソッドを使用して、reducers ディレクトリ内のレデューサーをマージしてエクスポートします。
import { combineReducers } from 'redux'
import userReducer from './user.reducer'
export default combineReducers({ userReducer })
クライアントのプロバイダーを構成し、ルート ディレクトリに gatsby-browser.js ファイルを作成し、wrapRootElement メソッドをエクスポートします。
const React = require('react')
const Layout = require('./src/components/Layout').default
const { Provider } = require('react-redux')
const createStore = require('./src/store/createStore').default
module.exports = {
wrapPageElement: ({ element }) => {
return <Layout>{element}</Layout>
},
wrapRootElement: ({ element }) => {
return <Provider store={createStore()}>{element}</Provider>
}
}
サーバー側でプロバイダーを構成し、ルート ディレクトリに gatsby-ssr.js ファイルを作成します。
const React = require('react')
const { Provider } = require('react-redux')
const createStore = require('./src/store/createStore').default
module.exports = {
wrapRootElement: ({ element }) => {
return <Provider store={createStore()}>{element}</Provider>
}
}
ストア内のデータを使用し、ページまたはコンポーネント内のデータを変更します
useDispatch、useSelector フック関数をコンポーネントに導入し、それらを使用してストア内の状態を変更します。
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
export default function Header () {
const userReducer = useSelector(state => state.userReducer)
const dispatch = useDispatch()
return (
<nav className='navbar navbar-light'>
<div className='container'>
<a className='navbar-brand' href='index.html'>
conduit
</a>
<ul className='nav navbar-nav pull-xs-right'>
<li className='nav-item'>
{/* Add "active" class when you're on that page" */}
<a className='nav-link active'>Home</a>
</li>
{userReducer.loginStatus === 1 && (
<li className='nav-item'>
<a className='nav-link'>
{' '}
<i className='ion-compose' />
New Article{' '}
</a>
</li>
)}
<li className='nav-item'>
<a className='nav-link'>
{' '}
<i className='ion-gear-a' />
Settings{' '}
</a>
</li>
{userReducer.loginStatus === 0 && (
<>
<li className='nav-item'>
<a
onClick={() => dispatch({ type: 'login' })}
className='nav-link'
>
Sign in
</a>
</li>
<li className='nav-item'>
<a className='nav-link'>Sign up</a>
</li>
</>
)}
{userReducer.loginStatus === 1 && (
<li className='nav-item'>
<a
className='nav-link ng-binding'
ui-sref-active='active'
ui-sref='app.profile.main({ username: $ctrl.currentUser.username })'
>
<img className='user-pic' src={userReducer.avatar} />
{userReducer.name}
</a>
</li>
)}
</ul>
</div>
</nav>
)
}
redux の非同期処理サポート、redux-saga を追加
npm インストール redux-saga
src/store/sagas フォルダーを作成し、src/store/sagas/user.saga.js および src/store/sagas/root.saga.js を作成します。
// src/store/sagas/user.saga.js
import axios from 'axios'
import { takeEvery, put, delay } from 'redux-saga/effects'
function* login_async (action) {
console.log(action.payload)
const { data } = yield axios.post(
'https://api.realworld.io/api/users/login',
{
user: action.payload.user
}
)
yield put({ type: 'login', payload: data.user })
}
export default function* userSaga () {
yield takeEvery('login_async', login_async)
}
// src/store/sagas/root.saga.js
import { all } from 'redux-saga/effects'
import userSaga from './user.saga'
export default function* rootSga () {
yield all([userSaga()])
}
ページコンポーネントでは以下を使用します。
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
export default function Header () {
const userReducer = useSelector(state => state.userReducer)
const dispatch = useDispatch()
return (
<nav className='navbar navbar-light'>
<div className='container'>
<a className='navbar-brand' href='index.html'>
conduit
</a>
<ul className='nav navbar-nav pull-xs-right'>
<li className='nav-item'>
{/* Add "active" class when you're on that page" */}
<a className='nav-link active'>Home</a>
</li>
{userReducer.loginStatus === 1 && (
<li className='nav-item'>
<a className='nav-link'>
{' '}
<i className='ion-compose' />
New Article{' '}
</a>
</li>
)}
<li className='nav-item'>
<a className='nav-link'>
{' '}
<i className='ion-gear-a' />
Settings{' '}
</a>
</li>
{userReducer.loginStatus === 0 && (
<>
<li className='nav-item'>
<a
onClick={() => dispatch({ type: 'login' })}
className='nav-link'
>
Sign in
</a>
</li>
<li className='nav-item'>
<a
onClick={() =>
dispatch({
type: 'login_async',
payload: {
user: {
email: '[email protected]',
password: '111111'
}
}
})
}
className='nav-link'
>
Sign up
</a>
</li>
</>
)}
{userReducer.loginStatus === 1 && (
<li className='nav-item'>
<a
className='nav-link ng-binding'
ui-sref-active='active'
ui-sref='app.profile.main({ username: $ctrl.currentUser.username })'
>
<img className='user-pic' src={userReducer.image} />
{userReducer.username}
</a>
</li>
)}
</ul>
</div>
</nav>
)
}