展馆网站建设方案,sae wordpress 升级,做学校网站素材图片大全,邯郸网站建设邯郸网站制作提起 Redux 我们想到最多的应该就是 React-redux 这个库#xff0c;可是实际上 Redux 和 React-redux 并不是同一个东西, Redux 是一种架构模式#xff0c;源于 Flux。 React-redux 是 Redux 思想与 React 结合的一种具体实现。 在我们使用 React 的时候#xff0c;常常会遇…提起 Redux 我们想到最多的应该就是 React-redux 这个库可是实际上 Redux 和 React-redux 并不是同一个东西, Redux 是一种架构模式源于 Flux。 React-redux 是 Redux 思想与 React 结合的一种具体实现。 在我们使用 React 的时候常常会遇到组件深层次嵌套且需要值传递的情况如果使用 props 进行值的传递显然是非常痛苦的。为了解决这个问题React 为我们提供了原生的 context API但我们用的最多的解决方案却是使用 React-redux 这个基于 context API 封装的库。 本文并不介绍 React-redux 的具体用法而是通过一个小例子来了解下什么是 redux。
好了现在我们言归正传来实现我们自己的 redux。
一、最初
首先我们用 creat-react-app 来创建一个项目删除 src 下冗余部分只保留 index.js并修改 index.html 的 DOM 结构
# index.html
div idrootdiv idhead/divdiv idbody/div
/div我们在 index.js 中创建一个对象用它来储存、管理我们整个应用的数据状态并用渲染函数把数据渲染在页面
const appState {head: {text: 我是头部,color: red},body: {text: 我是body,color: green}
}function renderHead (state){const head document.getElementById(head)head.innerText state.head.text;head.style.color state.head.color;
}
function renderBody (state){const body document.getElementById(body)body.innerText state.body.text;body.style.color state.body.color;
}
function renderApp (state){renderHead(state);renderBody(state);
}
renderApp(appState);此时运行代码打开页面我们可以看到在 head 中已经出现了红色字体的‘我是头部’在 body 中出现了绿色字体的‘我是body’。
如果我们把 head 和 body 看作是 root 中的两个组件那么我们已经实现了一个全局唯一的 state 。这个 state 是全局共享的随处可调用的。 我们可以修改 head 的渲染函数来看下效果
function renderHead (state){const head document.getElementById(head)head.innerText state.head.text -- state.body.text;head.style.color state.head.color;state.body.text 我是经过 head 修改后的 body;
}我们看到在 head 渲染函数中我们不仅可以取用 body 属性的值还可以改变他的值。这样就存在一个严重的问题因为 state 是全局共用的一旦在一个地方改变了 state 的值那么所有用到这个值的组件都将受到影响而且这个改变是不可预期的显然给我们的代码调试增加了难度系数这样的结果是我们不愿意看到的
二、dispatch
现在看来在我们面前出现了一个矛盾我们需要数据共享但共享数据被任意的修改又会造成不可预期的问题 为了解决这个矛盾我们需要一个管家专门来管理共享数据的状态任何对共享数据的操作都要通过他来完成这样就避免了随意修改共享数据带来的不可预期的危害 我们重新定义一个函数用这个函数充当我们的管家来对我们的共享数据进行管理
function dispatch(state, action) {switch (action.type) {case HEAD_COLOR:state.head.color action.colorbreakcase BODY_TEXT:state.body.text action.textbreakdefault:break}
}我们来重新修改head 的渲染函数
function renderHead (state){const head document.getElementById(head)head.innerText state.head.text -- state.body.text;head.style.color state.head.color;dispatch(state, { type: BODY_TEXT, text: 我是 head 经过调用 dispatch 修改后的 body })
}参考 前端进阶面试题详细解答
dispatch 函数接收两个参数一个是需要修改的 state 另一个是修改的值。这时虽然我们依旧修改了 state 但是通过 dispatch 函数我们使这种改变变得可控因为任何改变 state 的行为我们都可以在 dispatch 中找到改变的源头。 这样我们似乎已经解决了之前的矛盾我们创建了一个全局的共享数据而且严格的把控了任何改变这个数据的行为。 然而在一个文件中我们既要保存 state 还要维护管家函数 dispatch随着应用的越来越复杂这个文件势必会变得冗长繁杂难以维护。 现在我们把 state 和 dispatch 单独抽离出来
用一个文件单独保存 state用另一个文件单独保存 dispatch 中修改 state 的对照关系 changeState最后再用一个文件把他们结合起来生成全局唯一的 store
这样不仅使单个文件变得更加精简而且在其他的应用中我们也可以很方便的复用我们这套方法只需要传入不同应用的 state 和修改 state 的对应逻辑 stateChange就可以放心的通过调用 dispatch 方法对数据进行各种操作了
# 改变我们的目录结构新增 redux 文件夹srcredux
--- state.js // 储存应用数据状态
--- storeChange.js // 维护一套修改 store 的逻辑,只负责计算返回新的 store
--- createStore.js // 结合 state 和 stateChange , 创建 store ,方便任何应用引用
--index.js ## 修改后的各个文件# state.js -- 全局状态
export const state {head: {text: 我是头部,color: red},body: {text: 我是body,color: green}
}# storeChange.js -- 只负责计算修改 store
export const storeChange (store, action) {switch (action.type) {case HEAD_COLOR:store.head.color action.colorbreakcase BODY_TEXT:store.body.text action.textbreakdefault:break}
}# createStore.js -- 创建全局 store
export const createStore (state, storeChange) {const store state || {};const dispatch (action) storeChange(store, action);return { store, dispatch }
}# index.js
import { state } from ./redux/state.js;
import { storeChange } from ./redux/storeChange.js;
import { createStore } from ./redux/createStore.js;
const { store, dispatch } createStore(state, storeChange)function renderHead (state){const head document.getElementById(head)head.innerText state.text;head.style.color state.color;
}
function renderBody (state){const body document.getElementById(body)body.innerText state.text;body.style.color state.color;
}function renderApp (store){renderHead(store.head);renderBody(store.body);
}
// 首次渲染
renderApp(store);通过以上的文件拆分我们看到不仅使单个文件更加精简文件的职能也更加明确
在 state 中我们只保存我们的共享数据在 storeChange 中我们来维护改变 store 的对应逻辑计算出新的 store在 createStore 中我们创建 store在 index.js 中我们只需要关心相应的业务逻辑
三、subscribe
一切似乎都那么美好可是当我们在首次渲染后调用 dispatch 修改 store 时我们发现虽然数据被改变了可是页面并没有刷新只有在 dispatch 改变数据后,重新调用 renderApp() 才能实现页面的刷新。
// 首次渲染
renderApp(store);
dispatch({ type: BODY_TEXT, text: 我是调用 dispatch 修改的 body }) // 修改数据后页面并没有自动刷新
renderApp(store); // 重新调用 renderApp 页面刷新这样显然并不能达到我们的预期我们并不想在每次改变数据后手动的刷新页面如果能在改变数据后自动进行页面的刷新当然再好不过了 如果直接把 renderApp 写在 dispatch 里显然是不太合适的这样我们的 createStore 就失去了通用性。 我们可以在 createStore 中新增一个收集数组把 dispatch 调用后需要执行的方法统一收集起来然后再循环执行这样就保证了 createStore 的通用性
# createStore
export const createStore (state, storeChange) {const listeners [];const store state || {};const subscribe (listen) listeners.push(listen); const dispatch (action) {storeChange(store, action);listeners.forEach(item {item(store);})};return { store, dispatch, subscribe }
}# index.js
···
const { store, dispatch, subscribe } createStore(state, storeChange)
···
···
// 添加 listeners
subscribe((store) renderApp(store));
renderApp(store);
dispatch({ type: BODY_TEXT, text: 我是调用 dispatch 修改的 body });这样我们每次调用 dispatch 时页面就会重新刷新。如果我们不想刷新页面只想 alert 一句话只需要更改添加的 listeners 就好了
subscribe((store) alert(页面刷新了));
renderApp(store);
dispatch({ type: BODY_TEXT, text: 我是调用 dispatch 修改的 body });这样我们就保证了 createStore 的通用性。
四、优化
到这里我们似乎已经实现了之前想达到的效果我们实现了一个全局公用的 store 而且这个 store 的修改是经过严格把控的并且每次通过 dispatch 修改 store 后都可以完成页面的自动刷新。 可是显然这样并不足够以上的代码仍有些简陋存在严重的性能问题
虽然我们只是修改了 body 的文案可是在页面重新渲染时head 也被再次渲染。那么我们是不是可以在页面渲染的时候来对比新旧两个 store 来感知哪些部分需要重新渲染哪些部分不必再次渲染呢 根据上面的想法我们再次来修改我们的代码:
# storeChange.js
export const storeChange (store, action) {switch (action.type) {case HEAD_COLOR:return { ...store, head: { ...store.head, color: action.color }}case BODY_TEXT:return { ...store,body: {...store.body,text: action.text}}default:return { ...store }}
}# createStore.js
export const createStore (state, storeChange) {const listeners [];let store state || {};const subscribe (listen) listeners.push(listen);const dispatch (action) {const newStore storeChange(store, action);listeners.forEach(item {item(newStore, store);})store newStore; };return { store, dispatch, subscribe }
}# index.js
import { state } from ./redux/state.js;
import { storeChange } from ./redux/storeChange.js;
import { createStore } from ./redux/createStore.js;
const { store, dispatch, subscribe } createStore(state, storeChange);function renderHead (state){console.log(render head);const head document.getElementById(head)head.innerText state.text;head.style.color state.color;
}
function renderBody (state){console.log(render body);const body document.getElementById(body)body.innerText state.text;body.style.color state.color;
}function renderApp (store, oldStore{}){if(store oldStore) return; store.head ! oldStore.head renderHead(store.head); store.body ! oldStore.body renderBody(store.body); console.log(render app,store, oldStore);
}
// 首次渲染
subscribe((store, oldStore) renderApp(store, oldStore));
renderApp(store);
dispatch({ type: BODY_TEXT, text: 我是调用 dispatch 修改的 body });以上我们修改了 storeChange 让他不再直接修改原来的 store而是通过计算返回一个新的 store 。我们又修改了 cearteStore 让他接收 storeChange 返回的新 store 在 dispatch 修改数据并且页面刷新后把新 store 赋值给之前的 store 。而在页面刷新时我们来通过比较 newStore 和 oldStore 感知需要重新渲染的部分完成一些性能上的优化。
最后
我们通过简单的代码例子简单了解下 redux虽然代码仍有些简陋可是我们已经实现了 redux 的几个核心理念
应用中的所有state都以一个object tree的形式存储在一个单一的store中。唯一能改store的方法是触发actionaction是动作行为的抽象。