redux使用数据流程如下:
由上可知,我们需要一个函数来保存状态值,并暴露出修改,获取,同步的方法,下面开始进行推理
准备工作
没有react-create-app,安装后再创建reduxLearn
npm install -g create-react-app
react-create-app reduxLearn
开始操刀制作新鲜的redux
关于createStore
删除public和src下所有的文件,创建reduxLearn/public/index.html
新建reduxLearn/src/index.js
设置一个变量来保存我们想要的效果
let state = {
title: {
color: 'red',
text: '标题'
},
content: {
color: 'pink',
text: '内容'
}
}
创建渲染方法
function renderApp(appState) {
renderTitle(appState.title)
renderContent(appState.content)
}
function renderTitle(title) {
let titleEle = document.getElementById('title')
titleEle.innerHTML = title.text
titleEle.style.color = title.color
}
function renderContent(content) {
let contentEle = document.getElementById('content')
contentEle.innerHTML = content.text
contentEle.style.color = content.color
}
function render() {
renderApp(state)
}
如果在执行 renderApp(initState)之前的某个地方执行了initState=null
页面就会报错 TypeError: Cannot read property 'title' of null
为了是initState不被胡乱修改,我们需要搞个函数把它保护起来createStore
function createStore() {
let state = {
title: {
color: 'red',
text: '标题'
},
content: {
color: 'pink',
text: '内容'
}
}
}
变量被保护起来了,需要用的时候怎么获取呢?
需要提供getState暴露出变量的结果
function createStore() {
let state = {
title: {
color: 'red',
text: '标题'
},
content: {
color: 'pink',
text: '内容'
}
}
//获取状态
function getState() {
return state
}
return {
getState
}
}
//使用状态
let store = createStore(reducer)
...
function render() {
renderApp(store.getState())
}
如果我们想改变这个状态的值怎么办呢?
提供dispatch,但是你要需要告诉我改变什么,怎么改变即action
-
定义类型
const TITLE_COLOR = 'TITLE_COLOR' const TITLE_TEXT = 'TITLE_TEXT' const CONTENT_COLOR = 'CONTENT_COLOR' const CONTENT_TEXT = 'CONTENT_TEXT'
-
创建dispatch方法,暴露出来
//派发 function dispatch(action) { switch (action.type) { case TITLE_COLOR: state.title.color = action.color break; case TITLE_TEXT: state.title.text = action.text break; case CONTENT_COLOR: state.content.color = action.color break; case CONTENT_TEXT: state.content.text = action.text break; default: return state } }
-
调用dispatch
store.dispatch({ type: TITLE_COLOR, color: 'blue' }) store.dispatch({ type: TITLE_TEXT, text: '修改标题了' }) render()
-
看效果
在实际开发中初始状态state和操作步骤dispatch不是固定的我们需要提取出来
function createStore(reducer) {
let state;
//派发
function dispatch(action) {
state = reducer(state, action)//通过reducer处理返回结果值
}
//获取状态
function getState() {
return state
}
//执行一次,目的是设置默认值
dispatch({ type: "@@TYPE_INIT_STATE" })
return {
dispatch,
getState,
}
}
-
现在开始写reducer 函数,需要状态值和操作类型两个参数
//声明初始值 const initState = { title: { color: 'red', text: '标题' }, content: { color: 'pink', text: '内容' } } //reducer 这里返回的数据应是新对象->state = reducer(state, action)//通过reducer处理返回结果值 function reducer(state = initState, action) { switch (action.type) { case TITLE_COLOR: return { ...state, title: { ...state.title, color: action.color } } case TITLE_TEXT: state.title.text = action.text return { ...state, title: { ...state.title, text: action.text } } case CONTENT_COLOR: state.content.color = action.color return { ...state, content: { ...state.content, color: action.color } } case CONTENT_TEXT: return { ...state, content: { ...state.content, text: action.text } } default: return state } }
-
修改引用
let store = createStore(reducer)
发现每次修改都要重新调用render()才生效,很麻烦,如果我们在每次修改时添加监听事件,触发订阅模式,则可以一劳永逸
添加订阅函数
-
订阅函数
function createStore(reducer) { let state; //订阅添加监听函数数组 let listeners = [] //派发 function dispatch(action) { state = reducer(state, action) //订阅 listeners.forEach(l => l()) } //订阅,返回一个取消订阅的方法 function subscribe(listener) { listeners.push(listener) return function () { listeners = listeners.filter(item => item != listener) }
} //获取状态 function getState() { return state } dispatch({ type: "@@TYPE_INIT_STATE" }) return { dispatch, getState, subscribe }}
-
调用时订阅函数
store.subscribe(render)
-
测试订阅函数和取消订阅函数
store.subscribe(render)
setTimeout(() => { store.dispatch({ type: TITLE_COLOR, color: 'blue' }) store.subscribe(render)()//取消订阅 store.dispatch({ type: TITLE_TEXT, text: '修改标题了' }) }, 1000);
-
效果如下
提取createStore函数
-
新建reduxLearn/src/redux/createStore.js
export default function createStore(reducer) { let state; let listeners = [] //派发 function dispatch(action) { state = reducer(state, action) //订阅 listeners.forEach(l => l()) } //订阅,返回一个取消订阅的方法 function subscribe(listener) { listeners.push(listener) return function () { listeners = listeners.filter(item => item != listener) }
} //获取状态 function getState() { return state } dispatch({ type: "@@TYPE_INIT_STATE" }) return { dispatch, getState, subscribe }}
-
新建reduxLearn/src/redux/index.js
import createStore from './createStore' export { createStore, }
-
在使用时直接调用就可以使用了
import { createStore } from './redux'
createStore总结
要想保护数据要找个函数包裹起来createStore,可变的因素reducer可以通过参数传递进来,对数据的操作可以在函数内部暴露给外面getstate,dispatch,subscribe
在使用时直接把使用函数赋值给变量store,使用变量.函数store.getState()即可