手挽手带你学React入门四档,用人话教你react-redux,理解redux架构,以及运用在react中。学完这一章,你就可以开始自己的react项目了。
之前在思否看到过某个大神的redux搭建 忘记了大神的名字 这里只记得内容了 凭借记忆和当时的学习路线写下本文 隔空感谢
本人学习react-redux的时候遇到了很多坎,特别是不理解为什么这么用,这是什么东西,用来做什么。加上各种名词让人无法理解,所以这里我决定用人话,从原理走起,一步一步教大家使用react-redux。
开始之前本文开始之前,你需要先了解一些东西,当然我会在文中都一一教给大家。
首先你要会React的基础(这是废话)React上下文 context
对高阶函数有一定的了解
有ES6基础
满足这三项我们开始往下看。
react官网说,context这个东西你可能永远用不到,但是如果你使用了react-redux那么你还是无意间就使用到了它了。
那么它是个什么东西呢?你可以把它理解为全局的一个可以传递数据的东西,毕竟官方都没给出对于context的定义。
我们直接来看看它是怎么样来让数据可以全局使用的
在使用 context之前 你需要先认识这几个东西
首先需要
import PropTypes from "prop-types";
prop-types这个东西是一个帮你做类型检测的 所以我们直接就使用好了
接下来是 childContextTypes 这个属性 它是一个对象,里面规定我们要通过context来传递给下面的属性名和类型 它通常在父组件中
然后是 getChildContext(){} 这是个规定好的方法 内部retrun一个对象 用来初始化 context的数据
最后是 contextTypes 这个属性 它也是一个对象,里面规定我们要接收context来传递给下面的属性名和类型 它通常在子组件中
好了 了解了的话 我们开始写第一个 context了
// App.js import React,{Component} from "react" import PropTypes from "prop-types" //引入 export default class App extends Component { static childContextTypes = { //声明要通过context传递的东西 propA: PropTypes.string, methodA: PropTypes.func } getChildContext () { //初始化context return { propA: "propA", methodA: () => "methodA" } } constructor(){ super() this.state={ } } componentWillMount(){ // console.log(hashHistory) } render() { return () } } // 为了展示效果定义子组件一 class Children extends Component{ constructor(){ super() this.state={ } } static contextTypes = { //规定要接收的东西 propA: PropTypes.string } render(){ console.log(this.context.methodA) // 因为没有规定 所以现在是 undefined return( ) } } // 为了展示效果定义子组件二 ChildrenTwo 是 Children的子组件 但是却通过context拿到了App组件拿过来的值 (越级传递) class ChildrenTwo extends Component{ static contextTypes={ methodA: PropTypes.func } constructor(){ super() this.state={ } } render(){ return({this.context.propA}
{/* 展示propA */}) } }{this.context.methodA()}
{/* 展示methodA */}
通俗一点来说 一个组件 通过 getChildContext方法来返回一个对象 这就是我们的context 经过了 childContextTypes 声明后 它的下层组件都可以通过 contextTypes 声明。然后通过this.context获取到内容并且使用了。
好了 context这里就讲完了,大家把它放到你大脑的后台里运行着,可能在这里你一头雾水,讲这个干毛。好的,我们接下来实现一个redux架构!
从零开始Redux我们创建一个HTML文件,就叫redux.html 所有东西我们写在这一个html里面。
Document
上面的代码,通过函数渲染把状态内的东西渲染到了视图中,但是,这里的状态是暴露在外面的,任何一个地方都可以修改这个数据。这样就不存在稳定性可言了,我们想象一下,如果我们现在规定,你主动修改的state让程序直接无视掉,只有你通过我给你的方法去修改,我才会认可这个状态。因此 dispatch就出现了,这是修改数据唯一的地方。
Document
现在 你可以通过dispatch来修改state内容了,并且必须要按照它的声明方式,和修改方式有规律地修改了。
是时候创建一个store了我们现在有了数据,并且可以修改数据了,我们是不是可以创建我们的仓库了?它的名字叫做 store ,当然,如果我们手动把这些东西塞进去,那就显得太low了,使用函数作为一个工厂,帮我们生成这个那是极其舒坦的。
Document
到这里我们看到了一点Redux的雏形了,但是我们每次都要手动调用渲染,这是不是就非常地不爽。接下来我们要监听数据变化,让它自己渲染数据。那么这个监听在哪里呢?没错store里面
设置数据监听大家可能想到 我们如果把渲染数据加入到dispatch里面不就好了吗?没错,不过我们确实要在dispatch里面做文章。
function creatStore(state,stateChanger){ //这里我们创建一个函数 第一个参数是我们要用的状态仓 第二个是我们自己做的dispatch const getState = () => state const dispatch = (action)=> { stateChanger(state,action) // 这里我们改变了状态 然后我们需要刷新视图 renderApp(state) } //state就是我们放进来的状态 action是我们调用时候传进来 return{getState,dispatch} } const store = creatStore(state,dispatch) // 这里我们生成了store renderApp(store.getState()) // 渲染 store.dispatch({type:"UPDATE_HEAD_COLOR",color:"black"}) //改变state数值 store.dispatch({type:"UPDATE_HEAD_CONTEXT",context:"我变了"}) //改变state数值 // 现在我们可以监听数据变化了
但是这里我们遇到一个问题,这个creatStore只适用于我们当前的项目啊,不能够通用啊。这该怎么办呢?
其实简单 我们动态传入渲染的方法不就好了吗 于是我们把代码改成这样
function creatStore(state,stateChanger){ //这里我们创建一个函数 第一个参数是我们要用的状态仓 第二个是我们自己做的dispatch const getState = () => state const listenerList = [] const subscribe = (listener) => listenerList.push(listener) const dispatch = (action)=> { stateChanger(state,action) // 这里我们改变了状态 然后我们需要刷新视图 listenerList.map(item=>item()) } //state就是我们放进来的状态 action是我们调用时候传进来 return{getState,dispatch,subscribe} } const store = creatStore(state,stateChanger) // 这里我们生成了store store.subscribe(()=>renderApp(store.getState())) renderApp(store.getState()) // 渲染 store.dispatch({type:"UPDATE_HEAD_COLOR",color:"black"}) //改变state数值 store.dispatch({type:"UPDATE_HEAD_CONTEXT",context:"我变了"}) //改变state数值 // 现在我们可以动态加入监听了性能优化
写到这里 问题又出现了,每次我们改动一个数据 或者数据没有改动 只要是调用了 dispatch 我们就会触发全部的刷新 我们加上console.log看一下
// 然后我们声明三个渲染函数 function renderMyHead(myHead){ function renderMyHead(myHead){ console.log("渲染了Head") var DOM = document.getElementById("myHead") DOM.innerHTML = myHead.context DOM.style.color = myHead.color } function renderMyBody(myBody){ console.log("渲染了Body") var DOM = document.getElementById("myBody") DOM.innerHTML = myBody.context DOM.style.color = myBody.color } function renderApp(state){ console.log("渲染了App") renderMyHead(state.myHead) renderMyBody(state.myBody) }
加上这些console以后 你会发现 我们只改变了head 但是 body也被重新渲染了 这就大大浪费了性能啊 我们怎么办呢?没错 渲染之前检测一下数据变没变
不过我们先抛出一个问题
function renderMyHead(newMyHead,oldMyHead={}){ if(newMyHead==oldMyHead){ return } console.log("渲染了Head") var DOM = document.getElementById("myHead") DOM.innerHTML = newMyHead.context DOM.style.color = newMyHead.color } function renderMyBody(newMyBody,oldMyBody={}){ if(newMyBody===oldMyBody){ return } console.log("渲染了Body") var DOM = document.getElementById("myBody") DOM.innerHTML = newMyBody.context DOM.style.color = newMyBody.color } function renderApp (newState, oldState = {}) { if (newState === oldState) { return } renderMyHead(newState.myHead, oldState.myHead) renderContent(newState.myBody, oldState.myBody) } const store = creatStore(state,dispatch) // 这里我们生成了store let oldState = store.getState() store.subscribe(()=>{ const newState = store.getState() // 数据可能变化,获取新的 state renderApp(newState,oldState) //把新旧数据传禁区 oldState = newState //记录数据 }) renderApp(store.getState()) // 渲染 store.dispatch({type:"UPDATE_HEAD_COLOR",color:"black"}) //改变state数值 store.dispatch({type:"UPDATE_HEAD_CONTEXT",context:"我变了"}) //改变state数值
好的 到这里 问题来了,我们写这个有用吗?
答案显然易见 我们做这个等同于
let obj = {cc:1} let oldObj = obj obj.cc = 3 obj===oldObj // true
他们都指向了同一个地址呀 这有什么作用
所以我们现在要做的就是需要对 stateChanger内部的state返回模式进行改动,我们不再返回值,而是返回对象,当有对象返回的时候,我们的newState肯定就不等于oldState了,说到就做,尝试一下
Document
到这里我们已经搭建了自己的一个简单的redux了,我们继续往react-redux靠近
reducer我们上面写 creatStore的时候 传入了两个参数 state和 stateChanger 我们是不是可以把这两个也合并到一起呢?没问题 合并完了就是我们react-redux的reducer
// 我们就从stateChanger这个函数开始改 function stateChanger(state,action){ // 这里我们多加一个判断 是否有state 如果没有 我们就return一个 if(!state){ return{ myHead:{ color:"red", context:"我是脑袋" }, myBody:{ color:"blue", context:"我是身体" } } } switch (action.type){ case "UPDATE_HEAD_COLOR": return{ //这里我们使用ES6 不再去修改原来的state 而是 返回一个新的state 我们 creatStore里面的 dispatch方法也要跟着改动 ...state, myHead:{ ...state.myHead, color:action.color } } break; case "UPDATE_HEAD_CONTEXT": return{ ...state, myHead:{ ...state.myHead, context:action.context } } break; default: return{...state} break; } } function creatStore(stateChanger){ //现在我们不需要传入state了 只需要传入stateChanger 就好了 因为我们可以拿到它 let state = null const getState = () => state const listenerList = [] const subscribe = (listener) => listenerList.push(listener) const dispatch = (action)=> { state = stateChanger(state,action) //这里我们直接覆盖原来是state // 这里我们改变了状态 然后我们需要刷新视图 listenerList.map(item=>item()) } dispatch({}) // 这里初始化 state // 我们一切都声明完成 只需要调用一次 dispatch({}) 因为我们的state是null 所以 执行了 state = stateChanger(state,action) 从而得到了我们stateChanger内部设置的state了 return{getState,dispatch,subscribe} } const store = creatStore(stateChanger) // 这里我们生成了store 并且不用传入state了 只要把我们写好的 stateChanger放进去就好了 // 这个 stateChanger 官方称之为 reducer let oldStore = store.getState() //缓存旧数据 store.subscribe(()=>{ let newState = store.getState() //获得新数据 renderApp(newState,oldStore) //调用比较渲染 oldStore = newState //数据缓存 }) renderApp(store.getState()) store.dispatch({type:"UPDATE_HEAD_COLOR",color:"black"}) //改变state数值 store.dispatch({type:"UPDATE_HEAD_CONTEXT",context:"我变了"}) //改变state数值 // 经过我们一番改进 我们不再去调用Body的渲染了
到这里 你会突然发现,自己竟然动手实现了一套redux!我们要和react结合起来 还需要一个过程。
总结在我们四档上篇里面,从零开始搭建了一个自己的redux,这里面涉及到了太多高级的东西,大家需要好好消化,不理解的一定要留言提问~~
视频制作中文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/101642.html
摘要:手挽手带你学入门四档用人话教你,理解架构,以及运用在中。学完这一章,你就可以开始自己的项目了。结合搭建基础环境我们上一章讲过了的原理,内部是有一个的,只有才可以控制它变化。 手挽手带你学React入门四档,用人话教你react-redux,理解redux架构,以及运用在react中。学完这一章,你就可以开始自己的react项目了。 视频教程 上一篇我们自己实现了Redux,这一篇我们来...
摘要:当属性是一个回调函数时,函数接收底层元素或类实例取决于元素的类型作为参数。 手挽手带你学React入门第一期,带你熟悉React的语法规则,消除对JSX的恐惧感,由于现在开发中都是使用ES6语法开发React,所以这次也使用ES6的模式进行教学,如果大家对ES6不熟悉的话,先去看看class相关内容吧,这里我也慢慢带大家一步一步学会React。 视频教程 视频教程可移步我的个人博客:h...
摘要:手挽手带你学入门二档组件开发的开始,合理运用生命周期和组件,能够让你的开发变地流利又这篇文章带你学会创建组件,运用组建。 手挽手带你学React入门二档,组件开发的开始,合理运用生命周期和组件,能够让你的开发变地流利又happy,这篇文章带你学会创建组件,运用组建。学起来吧! React 组件生命周期 学习React,生命周期很重要,我们了解完生命周期的各个组件,对写高性能组件会有很大...
摘要:这样,我们用写的就写好了。真的假的大家可以看到,这些在插值表达式内的表达式直接返回了运行完成的结果,值得一提的是,差值表达式内的规则和标签内的规则是类似的。 视频教程 由于思否不能插入视频,视频请大家移步,http://www.henrongyi.top 什么是VUE VUE是一套用于构建用户界面的渐进式框架,VUE并不是一个真正意义上的mvvm框架,它更倾向是一种数据驱动框架.所以我...
摘要:这样,我们用写的就写好了。真的假的大家可以看到,这些在插值表达式内的表达式直接返回了运行完成的结果,值得一提的是,差值表达式内的规则和标签内的规则是类似的。 视频教程 由于思否不能插入视频,视频请大家移步,http://www.henrongyi.top 什么是VUE VUE是一套用于构建用户界面的渐进式框架,VUE并不是一个真正意义上的mvvm框架,它更倾向是一种数据驱动框架.所以我...
阅读 2177·2021-11-24 09:38
阅读 3241·2021-11-08 13:27
阅读 3082·2021-09-10 10:51
阅读 3142·2019-08-29 12:20
阅读 662·2019-08-28 18:28
阅读 3458·2019-08-26 11:53
阅读 2705·2019-08-26 11:46
阅读 1514·2019-08-26 10:56