使用方法
- createStore的使用
import {createStore} from 'redux'
function countReducer(state = 0, action){
switch(action.type){
case 'ADD':
return state + 1
case 'MINUS':
return state - 1
default:
return state
}
}
const store = createStore(countReducer)
export store
- subscribe和dispatch的使用
export default class reduxPage extends Component{
componentDidMount(){
this.unsubcribe = store.subscribe(()=>{
this.forceUpdate()
})
}
componentWillUnmount(){
this.unsubscribe()
}
add=()=>{
store.dispath({type: 'ADD'})
}
render(){
return(
<div>
<p>{store.getState()}</p>
<button onclick = {this.add}>add</button>
</div>
)
}
}
createStore源码实现
export default function createStore(reducer){
let currentState;
let currentListeners = []
function getState(){
return currentState
}
function dispatch(action){
currentState = reducer(currentState, action)
currentListeners.forEach((listener)=>listener())
}
function subscribe(listener){
currentListeners.push(listener)
return ()=>{
const index = currentListeners.indexOf(listener)
currentListeners.splice(index,1)
}
}
dispatch({type:'ADADADD/REDUX'})
return {
getState,
dispatch,
subscribe
}
}
Redux 支持异步(中间键)
也就是支持dispatch函数的形式
// 以上例子增加异步的情况
minus=()=>{
store.dispath((dispatch)=>{
setTimeout(()=>{
dispatch({type: 'MINUS'})
},1000)
})
}
前置知识compose
function f1(arg){
console.log('f1',arg)
return arg
}
function f2(arg){
console.log('f2',arg)
return arg
}
function f3(arg){
console.log('f3',arg)
return arg
}
//上一个函数的返回值是下一个函数的参数
const res = f1(f2(f3("omg")))
// compose的写法
const res = compose(f1,f2,f3)("omg")
function compose(...funcs){
if(funcs.length === 0){
return arg=>arg
}
if(funcs.length === 1){
return funcs[0]
}
return funcs.reduce((a,b)=>(...args)=>a(b(...args)))
}
引入中间键后,createStore变成如下引用方式
import {createStorem, applyMiddleware} from 'redux'
import thunk from "redux-thunk"
import logger from "redux-logger"
function countReducer(state = 0, action){
switch(action.type){
case 'ADD':
return state + 1
case 'MINUS':
return state - 1
default:
return state
}
}
const store = createStore(countReducer,applyMiddleware(thunk,logger))
export store
// createStore增强
export default function createStore(reducer,enhancer){
if(enhancer){
return enhancer(createStore)(reducer)
}
...
}
export default function applyMiddleware(...middlewares){
return (createStore)=>(reducer)=>{
const store = createStore(reducer)
let dispatch = store.dispatch
const midAPI = {
getState: store.getState,
dispatch: (action,...args)=>dispatch(action,...args)
}
const middlewareChain = middlewares.map((middleware)=>middleware(midAPI))
const dispatch = compose(...middlewareChain)(store.dispatch)
return {
...store,
dispatch
}
}
}
中间键logger的实现
function logger({getState, dispatch}){
return (next)=>(action)=>{
console.log('=========')
console.log("执行了"+action.type)
const prevState = getState()
console.log("prev state",prevState)
const returnValue = next(action)
const nextState = getState()
console.log("next State", nextState)
console.log('=========')
return returnValue
}
}
中间键thunk的实现
function thunk({getState, dispatch}){
return (next)=>(action)=>{
if(typeof action === "function"){
return action(dispatch, getState)
}
return next(action)
}
}
实现combineReducers
多个reducer的情况
const store = createStore(
combineReducers({
count: countReducer,
user: userReducer
})
)
使用的时候也通过键名来引用,store.getState().count或者store.getState().user
// 源码实现
export default function combineReducers(reducers){
return function combination(state = {}, action){
let nextState = {}
let hasChanges = false
for(const key in reducers){
const reducer = reducers[key]
nextState[key] = reducer(state[key], action)
hasChanged = hasChanged || nextState[key] !== state[key]
}
hasChanged = hasChanged || Object.keys(nextState).length!==Object.keys(state).length
return hasChanged ? nextState : state
}
}
react redux
Provider
// 引用
ReactDOM.render(
<Provider store = {store}>
<App>
</Provider>,
document.getElementById("root")
)
// 实现
// 1 创建context对象
const Context = React.createContext()
// 2 Provider 传递Value
export function Provider({store,children}){
return <Context.Provider value ={store}>{children}</Context.Provider>
}
connect
// 3 后代消费Provider传递下来的value
export const connect = (mapStateToProps,mapDispatchToProps)=>WrappedComponent=>props=>{
const store = useContext(Context)
const {getState, dispatch, subscribe} = store
const stateProps = mapStateToProps(getState())
const dispatchProps = {dispatch}
const forceUpdate = useForeceUpdate()
useLayoutEffect(()=>{
const unsubscribe = subscribe(()=>{
forceUpdate()
})
return ()=>{
unsubscribe()
}
},[subscribe])
return <WrappedComponent {...props} {...stateProps} {...dispatchProps} />
}
function useForceUpdate(){
const [state, setState] = useState(0)
const update = useCallback(()=>{
setState(prev=>prev+1)
},[])
return update
}
react-redux的hook api
- 使用方式
import {useSelector, useDispatch} from 'react-redux'
export default function ReactRduxHookPage(props){
const count = useSelector(({count}=>count))
const dispatch = useDispatch()
// 这里如果通过参数进行传递,还可以加useCallback
const add = useCallback(()=>{
()=>{
dispatch({type: "ADD"})
}
},[])
<!-- const add = ()=>{
dispatch({type: "ADD"})
} -->
return (
<div>
<button onClick = {add} >{count}</button>
</div>
)
}
- 源码实现
export function useSelector(selector){
const store = useContext(Context)
const {getState, subscribe} = store
const selectState = selector(getState())
useLayoutEffect(()=>{
const unSubscribe = subscribe(()=>{
forceUpdate
})
return ()=>{
unsubscribe()
}
},[subscribe])
return selectState
}
export function useDispatch(){
const store = useContext(Context)
const {dispatch} = store
return dispatch
}