现在我们有了状态,又有了dispatch,这时候我们需要一个高层管理者store,帮我们管理好他们,
所以我们就有了createStore这个函数帮我们生成store, 这样再用的时候就可以直接store.getState, store.dispatch的方式获取和更改组件状态。
function createStore(state, stateChanger) {
const getState = () => state;
const dispatch = (action) => stateChanger(state, action)
return {getState, dispatch}
}
createStore 接受两个参数,一个是表示app的 state。另外一个是 stateChanger,它来描述应用程序状态会根据 action 发生什么变化,其实就是相当于本节开头的 dispatch 代码里面的内容,我们后来会将它命名为reducer。
到了这一步,每当我想状态发生改变的时候,我就dispatch一个action来改变组件当前的状态。
但是这里还有一个问题,就是store里的数据发生改变之后,react是感知不到的。
如图:
所以我们需要手动在重新render一次APP。
整个过程如下:
let appState = {
title: {
text: ‘React.js’,
color: ‘red’,
},
content: {
text: ‘React.js内容’,
color: ‘blue’
}
}
function stateChanger (state, action) {
switch (action.type) {
case ‘UPDATE_TITLE_TEXT’:
state.title.text = action.text
break
case ‘UPDATE_TITLE_COLOR’:
state.title.color = action.color
break
default:
break
}
}
function createStore(state, stateChanger) {
const getState = () => state;
const dispatch = (action) => stateChanger(state, action)
return {getState, dispatch}
}
const store = createStore(appState, stateChanger)
renderApp(store.getState()) // 首次渲染页面
store.dispatch({ type: ‘UPDATE_TITLE_TEXT’, text: ‘《Redux》’ }) // 修改标题文本
store.dispatch({ type: ‘UPDATE_TITLE_COLOR’, color: ‘blue’ }) // 修改标题颜色
// 注意:这里需要我们手动重新render
renderApp(store.getState()) // 把新的数据渲染到页面上
这时候就需要观察者模式,react订阅store数据的改变,然后自动调用renderApp。我们的把这个功能加入在store里,所以createStore功能又强大啦~
function createStore(state, reducer) {
const getState = () => state;
const listeners = [];
// 订阅函数
const subscribe = (listener) => {
listeners.push(listener)
}
const dispatch = (action) => {
reducer(state, action);
// 数据已发生改变就把所有的listener跑一遍
listeners.forEach((listener) => {
listener()
})
}
return {getState, dispatch, subscribe}
}
接着,我们就可以这样使用
function createStore (state, stateChanger) {
const listeners = []
const subscribe = (listener) => listeners.push(listener)
const getState = () => state
const dispatch = (action) => {
stateChanger(state, action)
listeners.forEach((listener) => listener())
}
return { getState, dispatch, subscribe }
}
function renderApp (appState) {
renderTitle(appState.title)
renderContent(appState.content)
}
function renderTitle (title) {
const titleDOM = document.getElementById(‘title’)
titleDOM.innerHTML = title.text
titleDOM.style.color = title.color
}
function renderContent (content) {
const contentDOM = document.getElementById(‘content’)
contentDOM.innerHTML = content.text
contentDOM.style.color = content.color
}
let appState = {
title: {
text: ‘React.js’,
color: ‘red’,
},
content: {
text: ‘React.js内容’,
color: ‘blue’
}
}
// stateChanger 实际就是我们的reducer
function stateChanger (state, action) {
switch (action.type) {
case ‘UPDATE_TITLE_TEXT’:
state.title.text = action.text
break
case ‘UPDATE_TITLE_COLOR’:
state.title.color = action.color
break
default:
break
}
}
const store = createStore(appState, stateChanger)
// 监听数据变化,每次数据改变都会自动执行renderApp
store.subscribe(() => renderApp(store.getState()))
renderApp(store.getState()) // 首次渲染页面
store.dispatch({ type: ‘UPDATE_TITLE_TEXT’, text: ‘《Redux》’ }) // 修改标题文本
store.dispatch({ type: ‘UPDATE_TITLE_COLOR’, color: ‘blue’ }) // 修改标题颜色
这样,我们的renderApp 就会监听状态变化,每当dispatch一次action,它都会被自动执行。
流程图如下:
到这一步,一个APP就已经可以无压力的跑起来啦,最后一步,当然是关注性能,我们这个app 还是有严重性能问题的,因为每一次的dispatch 一次action,不管数据有没有变化,组件都会被重新渲染,这当然是不必要的。
为什么reducer是纯函数
所以就需要对reducer产生的前后appState进行一个对比,这就要求reducer必须是一个纯函数,返回的是一个新的object,这样才能够对比可以通过对比前后的state是否相等,来决定是否re-render
// reducer用来管理状态变化
function reducer (state, action) {
switch (action.type) {
case ‘CHANGE_TITLE’:
return {
…state,
title: {
…state.title,
text: action.text
}
}
case ‘CHANGE_CONTENT’:
return {
…state,
content: {
…state.content,
color: action.color
}
}
}
}
function createStore(state, reducer) {
let appState = state;
const getState = () => appState;
const listeners = [];
const subscribe = (listener) => {
listeners.push(listener)
}
const dispatch = (action) => {
// 覆盖原先的appState,可以看到:由于reducer返回的是一个新的object,那在外层,
// 我们就可以通过对比nextProps跟t his.props 来决定是否重新渲染
appState = reducer(state, action);
listeners.forEach((listener) => {
listener()
})
}
return {getState, dispatch, subscribe}
}
OK,到这一步,我们的redux就基本完成啦~ 接着改装下我们的reducer,让它有一个初始值,这样我们的createStore就只需要传入一个reducer即可
function reducer (state, action) {
//设置初始值
if(!state) {
return appState;
}
switch (action.type) {
case ‘CHANGE_TITLE’:
return {
…state,
title: {
…state.title,
text: action.text
}
}
case ‘CHANGE_CONTENT’:
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
[外链图片转存中…(img-Nw0IdDSZ-1715588741182)]
[外链图片转存中…(img-naZVxVKs-1715588741183)]
[外链图片转存中…(img-qrqGpYbL-1715588741183)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!