redux的基本使用
1,创建reducers
2,用reducers创建一个store
3,组件使用store的subscribe订阅store,当store的状态修改的时候,会自动进行更新
4,组件通过store的dispatch派发action,从而达到修改store的状态
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { createStore } from 'redux'
let defaultState = {
inputValue: 3
}
let reducers = (state = defaultState, action) => {
let newState = Object.assign({}, state);
if(action.type=='add') {
newState.inputValue += 1;
return newState;
} else if (action.type=='decrease') {
newState.inputValue -= 1;
return newState;
}
return newState;
}
let store = createStore(reducers);
class App extends React.Component {
constructor(){
super()
this.stateChange = this.stateChange.bind(this);
store.subscribe(this.stateChange);
this.state={
inputValue:0
}
}
render() {
return (
<div>
value:{this.state.inputValue}
<button onClick={this.addChange}>加一加</button>
<button onClick={this.decreaseChange}>剪一剪</button>
</div>
)
}
stateChange(){
this.setState({
inputValue:store.getState().inputValue
})
}
addChange(){
store.dispatch({
type:"add",
value:1
})
}
decreaseChange(){
store.dispatch({
type:"decrease",
value:1
})
}
}
ReactDOM.render(<App></App>,document.getElementById('root'))
reducx源码结构
src目录结构:utils下面是工具类
首先从工具类看起,其他核心模块会引用到工具类。
ActionTypes.js:
const randomString = () =>
Math.random()
.toString(36)
.substring(7)
.split('')
.join('.')
const ActionTypes = {
INIT: `@@redux/INIT${randomString()}`,
REPLACE: `@@redux/REPLACE${randomString()}`,
PROBE_UNKNOWN_ACTION: () => `@@redux/PROBE_UNKNOWN_ACTION${randomString()}`
}
export default ActionTypes
这个类很简单,定义了内部使用的action类型
isPlainObject.js:
export default function isPlainObject(obj) {
if (typeof obj !== 'object' || obj === null) return false
let proto = obj
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto)
}
return Object.getPrototypeOf(obj) === proto
}
定义一个判断对象是否是简单对象的方法。
warning.js:
export default function warning(message) {
/* eslint-disable no-console */
if (typeof console !== 'undefined' && typeof console.error === 'function') {
console.error(message)
}
}
定义一个通用的抛出错误警告的方法
index.js:
export {
createStore,
combineReducers,
bindActionCreators,
applyMiddleware,
compose,
__DO_NOT_USE__ActionTypes
}
index是redux的入口,导出了redux所有对外暴露的api
createStore.js:
createStore(reducer, preloadedState, enhancer)
createStore有三个参数:
reducer:处理action的函数,接受action,返回新的state
preloadedState:是一个预置状态,很少用
enhancer:store的增强器,可以增强store的功能
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState
preloadedState = undefined
}
当createStore只传入两个参数的时候,会将第二个参数的值赋值给enhancer,所以,使用的时候可以直接省略第二个参数,直接使用enhancer
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
return enhancer(createStore)(reducer, preloadedState)
}
这里可以看到enhancer对createStore进行了封装增强
let currentReducer = reducer //当前的reducer
let currentState = preloadedState //当前的state
let currentListeners = [] //当前的订阅者
let nextListeners = currentListeners //最新的订阅者
let isDispatching = false //用来锁定state资源
isDispatching:用来锁定state
currentListeners和nextListeners主要是用来当正在通知的时候不会打乱当前的订阅者的顺序。
function getState() {
if (isDispatching) {
throw new Error(
'You may not call store.getState() while the reducer is executing. ' +
'The reducer has already received the state as an argument. ' +
'Pass it down from the top reducer instead of reading it from the store.'
)
}
return currentState
}
当getState()的时候,会判断当前资源是不是在被占用,如果在占用,就会抛出异常。
function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error('Expected the listener to be a function.')
}
if (isDispatching) {
throw new Error(
'You may not call store.subscribe() while the reducer is executing. ' +
'If you would like to be notified after the store has been updated, subscribe from a ' +
'component and invoke store.getState() in the callback to access the latest state. ' +
'See https://redux.js.org/api-reference/store#subscribelistener for more details.'
)
}
let isSubscribed = true
ensureCanMutateNextListeners()
nextListeners.push(listener)
return function unsubscribe() {
if (!isSubscribed) {
return
}
if (isDispatching) {
throw new Error(
'You may not unsubscribe from a store listener while the reducer is executing. ' +
'See https://redux.js.org/api-reference/store#subscribelistener for more details.'
)
}
isSubscribed = false
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
currentListeners = null
}
}
首先判断订阅者传递的是不是一个函数,然后store中的资源有没有被占用。最后返回一个解除订阅者的函数
function dispatch(action) {
if (!isPlainObject(action)) {
throw new Error(
'Actions must be plain objects. ' +
'Use custom middleware for async actions.'
)
}
if (typeof action.type === 'undefined') {
throw new Error(
'Actions may not have an undefined "type" property. ' +
'Have you misspelled a constant?'
)
}
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.')
}
try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
}
dipatch处理用户传入的action,reducer根据action的type对store中的state进行更改,返回新的state赋值给currentState.然后循环当前的所有订阅者,通知store的更新。