把之前学习redux的手写学习笔记分享出来一下,方便大家理解redux思想,毕竟前端工程师里面都说,
初级前端和中级前端的区别就是是否懂设计模式和面向对象
这个是将redux思想的一个拆分, 将 redux 拆分成 5 部分,最终拼成一个react redux,
为什么使用react redux ?
有了redux之后 state不再是谁都可以任意调用setState修改的数据了,
react没有redux 和 有redux的核心区别**
react: 通过 setState修改state数据,再执行渲染;
react-redux: 通过 dispatch来判断是否执行setState,dispatch检测通过,执行setState函数, 否则不予执行;
1. 引入dispatch管理对setState的调用
<div id="title"></div>
<div id="contents"></div>
<script>
// 渲染模块
function render() {
document.getElementById('title').innerHTML = state.title;
document.getElementById('contents').innerHTML = state.content;
}
//数据模块
var state = {
title: '新的标题',
content: '新的内容'
}
//初次渲染执行
render();
//更改数据模块 ** 更改后触发数据渲染
function setState(newState) {
this.state = {
...state,
...newState
}
render()
}
</script>
下面这部分是redux思想的和体现方式, 通过dispath判断参数的type是否合法, 合法才可以可以调用setState
<script>
// 管理模块, 想要触发数据改变请执行这个函数, 并且要给指定的type, 否则不执行setState
var dispatch = function (action) {
switch (action.type) {
case 'CHANGE_TITLE': // 传过来的type正确才能setState
setState({
title: action.newTitle
})
break;
default:
break;
}
}
//修改数据调用dispatch函数, 只有里面的json的type经过了dispatch检测才能执行相应的setState
dispatch(
{
type: 'CHANGE_TITLE',
newTitle: '我是经过dispatch函数允许修改后的新标题'
}
)
</script>
2. 引入subscriber
<div id="title"></div>
<div id="contents"></div>
<script>
function render() {
document.getElementById('title').innerHTML = state.title;
document.getElementById('contents').innerHTML = state.content;
}
var state = {
title: '新的标题',
content: '新的内容'
}
render()
创建数组listeners, 引入订阅subscriber 函数,该函数向数组中订阅(push)新的事件,比如render渲染函数,在成功触发setState后,会对listensers数组里面的函数依次执行。
var dispatch = function (action) {
switch (action.type) {
case 'CHANGE_TITLE':
state = {
...state,
title:action.newTitle
}
break;
default:
break;
}
listeners.forEach(e=>e()) //依次执行数组中订阅的事件
}
var listeners = []; //这个数组放setState之后执行的事件,
var subscribe = function(listener){ //用subscriber函数把事件push到事件数组中
listeners.push(listener)
}
subscribe(render) // 数组中放入render函数
dispatch(
{
type: 'CHANGE_TITLE',
newTitle: '我是经过dispatch函数允许修改后的新标题'
}
)
</script>
</body>
3. 初步封装 createStore
div id="title"></div>
<div id="contents"></div>
<script>
//渲染函数
function render(state) {
document.getElementById('title').innerHTML = state.title;
document.getElementById('contents').innerHTML = state.content;
}
//store 核心部分
var createStore = function () {
//state数据
var state = {
title: '这是一个标题',
content: '这是一段内容'
}
//执行函数仓库
var listeners = [];
//获取state数据
var getState = function () {
return state;
}
//dispatch监控 type是否合法,合法才触发setState函数
var dispatch = function (action) {
switch (action.type) {
case 'CHANGE_TITLE':
state = {
...state,
title: action.newTitle
}
break;
default:
break;
}
listeners.forEach(e => e())
}
//事件订阅函数
var subscribe = function (listener) {
listeners.push(listener)
}
// 暴露调用接口
return {
dispatch,
subscribe,
getState
}
}
//调用部分
//创建实例化对象
var store = createStore();
//解构获取三个接口函数
var { subscribe, dispatch, getState } = store;
//订阅事件
subscribe(() => render(getState()));
//请求dispatch改变状态
dispatch(
{
type: 'CHANGE_TITLE',
newTitle: '我是经过dispatch函数允许修改后的新标题'
}
)
render(getState())
</script>
但是这个createStore函数存在不纯的问题,含有定好的state 和 dispatch,接下来就是对该函数进行提纯处理。
4. createStore函数提纯处理,让createStore 和 state,setState相分离 , 将state和setState放入appReducer函数中
<div id="title"></div>
<div id="contents"></div>
<script>
//store 核心部分
var createStore = function () {
// 将state设置为 null;
var state = null
var listeners = [];
var dispatch = function (action) {
//调用dispatch时, 执行appReducer做判断
state = appReducer(state, action);
listeners.forEach(e => e());
}
//调用dispatch初始化state,获取appReducer中的默认state。
dispatch({})
var subscribe = function (listener) {
listeners.push(listener)
}
var getState = function () {
return state;
}
//暴露接口
return {
dispatch,
subscribe,
getState
}
}
var appReducer = function (state, action) {
//初始化store中的state
//因为state初始值为null
if (!state) {
return {
title: '这是一个标题',
content: '这是一段内容'
}
}
//更新state
switch (action.type) {
case 'CHANGE_TITLE':
return {
...state,
title: action.newTitle
}
break;
default:
return state;
}
}
var store = createStore();
var { subscribe, dispatch, getState } = store;
subscribe(() => render(getState()))
dispatch(
{
type: 'CHANGE_TITLE',
newTitle: '我是经过dispatch函数允许修改后的新标题'
}
)
function render(state) {
document.getElementById('title').innerHTML = state.title;
document.getElementById('contents').innerHTML = state.content;
}
//调用部分
render(getState())
</script>
此时 createStore依然不是一个纯函数, 依然无法独立, 因为里面有写死的appReducer函数的执行;
5. 彻底让createStore变成纯函数 , appReducer作为参数传入到createStore。
// 现在已经是非常干净的纯函数了
function createStore(appReducer) {
state = null;
var listeners = [];
function dispatch(action) {
state = appReducer(state, action)
listeners.map(e => e())
}
dispatch({})
function getState() {
return state
}
function subscribe(listener) {
listeners.push(listener);
}
return {
dispatch,
getState,
subscribe
}
}
// appReucer 函数
function appReducer(state, action) {
//初始化数据
if (!state) {
return {
title: '你好',
content: '欢迎光临'
}
}
switch (action.type) {
case 'CHANGE_TITLE':
return {
...state,
title: action.newTitle
}
break;
default:
break;
}
}
//使用createStore部分
var store = createStore(appReducer);
var { dispatch,
getState,
subscribe } = store;
subscribe(() => render(getState()))
dispatch(
{
type: "CHANGE_TITLE",
newTitle: '我是经过dispatch函数允许修改后的新标题'
}
)
function render(state) {
document.getElementById('title').innerHTML = state.title;
document.getElementById('content').innerHTML = state.content;
}
render(getState());
至此,react redux 核心思想已经搞定了,相信你一定看得懂。
把自己写的createStore 应用在react中
store的三个接口:
dispatch, 修改store里面的state
subscribe, 订阅渲染组件的事件 this.setState
getState, 获取store里面的state
这样, 组件就无需维护自己的state 而使用外部引入的store里面的state
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import * as serviceWorker from './serviceWorker';
import createStore from './createStore';
let appReducer = (state, action) => {
if (!state) {
return {
title: "这个是标题",
content: "这个是内容"
}
}
switch (action.type) {
case "CHANGE_TITLE":
return {
...state,
title: action.newTitle
}
case "CHANGE_CONTENT":
return {
...state,
content: action.newContent
}
default:
return state;
}
}
var store = createStore(appReducer)
//组件将不用去维护自己的state
class App extends Component {
constructor() {
super();
//订阅触发渲染的事件 this.setState
store.subscribe(() => {
this.setState(store.getState)
})
}
_chengeTitle(newTitle) {
//调用dispatch去修改store中的state, 随后dispatch会 按顺序执行listeners数组中订阅的事件
store.dispatch({
type: "CHANGE_TITLE",
newTitle: newTitle
})
}
render() {
const { title, content } = store.getState();
{ console.info(store.getState()) }
return (
< div >
<h1>{title}</h1>
<p>{content}</p>
<button onClick={() => this._chengeTitle('您点击了按钮,标题已经被修改')}>点击</button>
</div >
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();