Redux 简单使用
npx create-react-app test-redux-demo
yarn add redux
import { createStore } from 'redux' ;
const actionTypes = {
ADD : "add" ,
SUB : "subtract" ,
}
const initState = { count: 0 }
const reducer = ( state = initState, action: { type: string, payload: number } ) => {
const type = action. type
const { ADD , SUB } = actionTypes
const { count } = state
if ( type === ADD ) {
return { count: count + action. payload }
}
if ( type === SUB ) {
return { count: count - action. payload }
}
return state
}
const store = createStore ( reducer)
export async function addAction ( count: number ) {
store. dispatch ( {
type: actionTypes. ADD ,
payload: count
} )
}
export function subAction ( count: number ) {
store. dispatch ( {
type: actionTypes. SUB ,
payload: count
} )
}
export default store
import { useEffect, useState } from 'react' ;
import store, { addAction, subAction } from '../redux/store' ;
export default function Todo ( ) {
const [ count, setCount] = useState ( store. getState ( ) . count)
useEffect ( ( ) => {
store. subscribe ( ( ) => {
setCount ( store. getState ( ) . count)
} )
} , [ ] )
return < >
{ }
< button onClick= { ( ) => addAction ( 1 ) } > + < / button>
< div> { count} < / div>
< button onClick= { ( ) => subAction ( 1 ) } > - < / button>
< / >
}
createStore 方法简单实现
const createStore = ( reducer ) => {
let state;
let listeners = [ ] ;
const getState = ( ) => state;
const dispatch = ( action ) => {
state = reducer ( state, action) ;
listeners. forEach ( listener => listener ( ) ) ;
} ;
const subscribe = ( listener ) => {
listeners. push ( listener) ;
return ( ) => {
listeners = listeners. filter ( l => l !== listener) ;
}
} ;
dispatch ( { } ) ;
return { getState, dispatch, subscribe } ;
} ;
使用 combineReducers 抽出 reducer
import store from "./store"
const actionTypes = {
ADD : "add" ,
SUB : "subtract" ,
}
const initState = { count: 0 }
export async function addAction ( count: number ) {
let n = await new Promise ( ( resolve ) => {
let timeout = setTimeout ( ( ) => {
clearTimeout ( timeout)
resolve ( count)
} , 1000 )
} )
store. dispatch ( {
type: actionTypes. ADD ,
payload: n as number
} )
}
export function subAction ( count: number ) {
store. dispatch ( {
type: actionTypes. SUB ,
payload: count
} )
}
const reducer = ( state = initState, action: { type: string, payload: number } ) => {
const type = action. type
const { ADD , SUB } = actionTypes
const { count } = state
if ( type === ADD ) {
return { count: count + action. payload }
}
if ( type === SUB ) {
return { count: count - action. payload }
}
return state
}
export default reducer
import { createStore, combineReducers } from 'redux' ;
import countReducer from './count' ;
const reducer = combineReducers ( {
countState: countReducer
} )
const store = createStore ( reducer)
export default store
import { useEffect, useState } from 'react' ;
import store from '../redux/store' ;
import { addAction, subAction } from '../redux/count'
export default function Todo ( ) {
const storeCount = store. getState ( ) . countState. count
const [ count, setCount] = useState ( storeCount)
console. log ( count)
useEffect ( ( ) => {
store. subscribe ( ( ) => {
setCount ( store. getState ( ) . countState. count)
} )
} , [ ] )
return < >
< button onClick= { ( ) => addAction ( 1 ) } > + < / button>
< div> { count} < / div>
< button onClick= { ( ) => subAction ( 1 ) } > - < / button>
< / >
}
简单异步
export async function addAction ( count: number ) {
let n = await new Promise ( ( resolve ) => {
let timeout = setTimeout ( ( ) => {
clearTimeout ( timeout)
resolve ( count)
} , 1000 )
} )
store. dispatch ( {
type: actionTypes. ADD ,
payload: n as number
} )
}
使用 applyMiddleware 添加中间件
import { createStore, combineReducers, applyMiddleware } from 'redux' ;
import reducer from './count' ;
import logger from 'redux-logger'
const store = createStore ( combineReducers ( {
countState: reducer
} ) ,
applyMiddleware ( logger)
)
export default store
function applyMiddleware ( ) {
for ( var _len = arguments. length, middlewares = new Array ( _len) , _key = 0 ; _key < _len; _key++ ) {
middlewares[ _key] = arguments[ _key] ;
}
return function ( createStore ) {
return function ( ) {
var store = createStore . apply ( void 0 , arguments) ;
var _dispatch = function dispatch ( ) {
throw new Error ( 'Dispatching while constructing your middleware is not allowed. ' + 'Other middleware would not be applied to this dispatch.' ) ;
} ;
var middlewareAPI = {
getState: store. getState,
dispatch : function dispatch ( ) {
return _dispatch . apply ( void 0 , arguments) ;
}
} ;
var chain = middlewares. map ( function ( middleware ) {
return middleware ( middlewareAPI) ;
} ) ;
_dispatch = compose . apply ( void 0 , chain) ( store. dispatch) ;
return _objectSpread2 ( _objectSpread2 ( { } , store) , { } , {
dispatch: _dispatch
} ) ;
} ;
} ;
}
function compose ( ) {
for ( var _len = arguments. length, funcs = new Array ( _len) , _key = 0 ; _key < _len; _key++ ) {
funcs[ _key] = arguments[ _key] ;
}
if ( funcs. length === 0 ) {
return function ( arg ) {
return arg;
} ;
}
if ( funcs. length === 1 ) {
return funcs[ 0 ] ;
}
return funcs. reduce ( function ( a, b ) {
return function ( ) {
return a ( b . apply ( void 0 , arguments) ) ;
} ;
} ) ;
}
简单使用 react-redux
import { actionTypes } from '../redux/count'
import { connect } from 'react-redux' ;
function Todo ( props: { onAdd: any; onSub: any; count: any; } ) {
const { onAdd, onSub, count } = props
return < >
< button onClick= { ( ) => onAdd ( 1 ) } > + < / button>
< div> { count} < / div>
< button onClick= { ( ) => onSub ( 1 ) } > - < / button>
< / >
}
const mapStateToProps = ( state: { countState: { count: number; } ; } , ownProps: any ) => {
console. log ( ownProps)
return {
count: state. countState. count
}
}
const mapDispatchToProps = ( dispatch : ( arg0: { type: string; payload: number; } ) => void , ownProps: any) => {
console. log ( ownProps)
return {
onAdd : async ( count: number ) => {
let n = await new Promise ( ( resolve ) => {
let timeout = setTimeout ( ( ) => {
clearTimeout ( timeout)
resolve ( count)
} , 1000 )
} )
dispatch ( {
type: actionTypes. ADD ,
payload: n as number
} )
} ,
onSub : ( count: number ) => {
dispatch ( {
type: actionTypes. SUB ,
payload: count
} )
}
}
}
export default connect (
mapStateToProps,
mapDispatchToProps
) ( Todo)
import './App.css' ;
import store from './redux/store'
import Todo from './page/Todo'
import { Provider } from 'react-redux'
function App ( ) {
return (
< Provider store= { store} >
< div className= "App" >
< Todo test= { 123 } > < / Todo>
< / div>
< / Provider >
) ;
}
export default App;
补充
const mapDispatchToProps = ( dispatch : ( arg0: { type: string; payload: number; } ) => void , ownProps: any) => {
return {
onAdd : ( count: number ) => {
dispatch ( {
type: actionTypes. ADD ,
payload: count
} )
} ,
onSub : ( count: number ) => {
dispatch ( {
type: actionTypes. SUB ,
payload: count
} )
}
}
}
const mapDispatchToProps = {
onAdd : ( count: number ) => {
return {
type: actionTypes. ADD ,
payload: count
}
} ,
onSub : ( count: number ) => {
return {
type: actionTypes. SUB ,
payload: count
}
}
}