博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
傻瓜式入门Redux
阅读量:7236 次
发布时间:2019-06-29

本文共 8385 字,大约阅读时间需要 27 分钟。

Redux 是一个 JavaScript 应用状态管理的库,当项目很复杂的时候,属性传递已经达不到我们预期,可以使用Redux 解决数据传递问题,统一状态管理。换句话说,Redux就是用来处理和管理应用的状态/数据。

Redux设计思想

  • Redux是将整个应用状态存储到到一个地方,称为store

  • 里面保存一棵状态树(state tree)

  • 组件可以派发(dispatch)行为(action)给store,而不是直接通知其它组件

  • 其它组件可以通过订阅store中的状态(state)来刷新自己的视图

Redux概念解析

Store

Redux的核心是一个store ,就是保存数据的地方,可以看出是一个容器,整个应用就只能有一个store。Redux提供createStore()函数来生成store。

import { createStore } from 'redux';let store = createStore(fn);复制代码

上面代码中,createStore函数接受另一个函数作为参数,返回新生成的Store对象。

State

store 某个节点对应的数据集合就是state。state 是被托管的数据,也就是每次触发监听事件,我们要操作的数据。可以通过store.getState()获得。

Redux 规定,一个state对应一个View。State相同,则View相同。

let store = createStore(fn);let state = store.getState();复制代码

Action

State 的变化,会导致 View 的变化。但是,用户接触不到 State,只能接触到 View。所以,State 的变化必须是 View 导致的。Action 就是 View 发出的通知,表示 State 应该要发生变化了。

Action 是一个对象。其中的type属性是必须的,表示 Action 的名称。其他属性可以自由设置。

{ type: types.ADD_TODO , text: '读书' }复制代码

Actor Creator

action creator 顾名思义就是用来创建 action 的,action creator 只简单的返回 action。

const ADD_TODO = 'ADD_TODO';let actions = {    addTodo(todo){        return { type: ADD_TODO, todo}    }}复制代码

store.dispath(action)

store.dispatch()是 View 发出 Action 的唯一方法。store.dispatch接受一个 Action 对象作为参数,将它发送出去

let store=createStore(reducer);store.dispatch({
type:'ADD_TODO',text:'读书'});复制代码

结合 Action Creator,这段代码可以改写如下。

store.dispatch(actions.addTodo(e.target.value))复制代码

Redux 核心API

createStore

使用方法

let store=createStore(reducer);

  • reducer

    在Redux中,负责响应action并修改数据的角色就是reducer。 reducer要有两个参数 ,要根据老的状态和新传递的动作算出新的状态。reducer本质上是一个纯函数,每次需要返回一个新的状态对象。

    //以下为reducer的格式const todo = (state = initialState, action) => {  switch(action.type) {      case 'XXX':          return //具体的业务逻辑;      case 'XXX':          return //具体的业务逻辑;         default:          return state;  }}复制代码
  • getState()

    将状态放到了容器中外部无法在进行更改了,使用获取store中的状态。

  • dispatch(action)

  • subscribe(listener)

combineReducers

合并reducer,把他们合并成一个

key是新状态的命名空间,值是reducer,执行后会返回一个新的reducer。

let reducer = combineReducers({    c: counter,    t: todo});复制代码

context

react提供一个context API,可以解决跨组件的数据传递。16.3版本以前的context和现在最新版context用法有区别。在16.3官方不推荐使用,如果某个组件shouldComponentUpdate返回了false后面的组件就不会更新了

contextAPI 新的方法非常简便。

import React from 'react';import {render} from 'react-dom';// 创建一个上下文,有两个属性 一个叫Provider 还有个叫Consume// createContext中的对象是默认参数let { Consumer,Provider} = React.createContext();// context 可以创建多个 这时候就不要解构了,不同的context是不能交互的class Title extends React.Component{    render(){        // 子类通过Consumer进行消费 内部必须是一个函数 函数的参数是Provider的value属性        return 
{({s,h})=>{ return
{ h('red'); }}>hello
}}
}}class Head extends React.Component{ render() { return
}}// Provider使用在父组件上class App extends React.Component{ constructor(){ super(); this.state = {color:'green'} } handleClick = (newColor) =>{ this.setState({ color: newColor}) } render(){ return
}}render(
,window.root)复制代码

实现简单的Redux

了解基本概念后就来写一个实现简单功能的"redux"吧!实现把内容渲染到页面上

1.渲染状态

//数据源let appState={    title: {color: 'red',text: '标题'},    content:{color:'green',text:'内容'}}// 渲染标题function renderTitle(title) {    let titleEle=document.querySelector('#title');    titleEle.innerHTML=title.text;    titleEle.style.color=title.color;}// 渲染内容function renderContent(content) {    let contentEle=document.querySelector('#content');    contentEle.innerHTML=content.text;    contentEle.style.color=content.color;}// 执行渲染的方法function render(appState) {    renderTitle(appState.title);    renderContent(appState.content);}render(appState);复制代码

2.提高数据修改的门槛

  • 状态不应该是全局的,也不应该哪个方法里直接可以更改(操作危险)

  • 一旦数据可以任意修改,所有对共享状态的操作都是不可预料的

  • 模块之间需要共享数据和数据可能被任意修改导致不可预料的结果之间有矛盾

  • 所以提供一个修改状态的dispatch方法,不要去直接更改状态,对数据的操作修改必须通过这个方法

let appState={    title: {color: 'red',text: '标题'},    content:{color:'green',text:'内容'}}function renderTitle(title) {    let titleEle=document.querySelector('#title');    titleEle.innerHTML=title.text;    titleEle.style.color=title.color;}function renderContent(content) {    let contentEle=document.querySelector('#content');    contentEle.innerHTML=content.text;    contentEle.style.color=content.color;}function render(appState) {    renderTitle(appState.title);    renderContent(appState.content);}//先定义好要做那些事情(常量) 也叫宏const UPDATE_TITLE_COLOR = 'UPDATE_TITLE_COLOR';const UPDATE_CONTENT_CONTENT = 'UPDATE_CONTENT_CONTENT';​// 派发的方法,用来更改状态// 派发时应该将修改的动作action提交过来,是个对象,对象里的type属性是固定必须的。function dispatch(action) {    switch (action.type) {        case UPDATE_TITLE_COLOR:            appState.title.color=action.color;                break;            case UPDATE_CONTENT_CONTENT:            appState.content.text=action.text;            break;        default:            break;        }}dispatch({
type:UPDATE_TITLE_COLOR,color:'purple'});dispatch({
type:UPDATE_CONTENT_CONTENT,text:'新标题'});​render(appState);复制代码

3.分装仓库

把状态放进一个容器里,将定义状态和规则的部分抽离到容器外面

function renderTitle(title) {    let titleEle=document.querySelector('#title');    titleEle.innerHTML=title.text;    titleEle.style.color=title.color;}function renderContent(content) {    let contentEle=document.querySelector('#content');    contentEle.innerHTML=content.text;    contentEle.style.color=content.color;}function render(appState) {    renderTitle(appState.title);    renderContent(appState.content);}// 容器function createStore(reducer) {    let state;    // 让外面可以获取状态    function getState() {        return state;    }​    function dispatch(action) {         state=reducer(state,action);    }    dispatch({});        // 将方法暴露给外面使用,将状态放到了容器中外部无法在进行更改了    return { getState , dispatch }}​// 容器一般会封装成库// 将定义状态和规则的部分抽离到容器外面,再传进去let initState={    title: {color: 'red',text: '标题'},    content:{color:'green',text:'内容'}}const UPDATE_TITLE_COLOR = 'UPDATE_TITLE_COLOR';const UPDATE_CONTENT_CONTENT = 'UPDATE_CONTENT_CONTENT';​// 用户自己定义的规则,我们叫它reducer,也就是所谓的管理员// reducer要有两个参数,要根据老的状态和新传递的动作算出新的状态// 如果想获取默认状态,有一种方式,就是调用reducer,让每一个规则都不匹配将默认值返回// 在reducer中,reducer是一个纯函数,每次需要返回一个新的状态,只承担计算 State 的功能let reducer=function (state=initState,action) {    switch (action.type) {        case UPDATE_TITLE_COLOR:            return {...state,title: {...state.title,color:action.color}};        case UPDATE_CONTENT_CONTENT:        return {...state,content: {...state.content,text:action.text}};                break;        default:            return state;        }}​let store=createStore(reducer);render(store.getState());setTimeout(function () {    store.dispatch({
type:UPDATE_TITLE_COLOR,color:'purple'}); store.dispatch({
type:UPDATE_CONTENT_CONTENT,text:'新标题'}); render(store.getState());},2000);复制代码

4.监控数据变化

function renderTitle(title) {    let titleEle=document.querySelector('#title');    titleEle.innerHTML=title.text;    titleEle.style.color=title.color;}function renderContent(content) {    let contentEle=document.querySelector('#content');    contentEle.innerHTML=content.text;    contentEle.style.color=content.color;}function render() {    renderTitle(store.getState().title);    renderContent(store.getState().content);}function createStore(reducer) {    let state;    let listeners=[];    function getState() {        return state;    }    // 发布订阅模式,先将render方法订阅好,每次dispatch时都调用订阅好的方法    function dispatch(action) { // 发布        state=reducer(state,action);        listeners.forEach(l=>l());    }​    function subscribe(listener) { // 订阅        listeners.push(listener);        return () => {            // 再次调用时 移除监听函数            listeners = listeners.filter(item => item!=listener);            console.log(listeners);        }    }    dispatch({});    return { getState,dispatch,subscribe }}let initState={    title: {color: 'red',text: '标题'},    content:{color:'green',text:'内容'}}let reducer=function (state=initState,action) {    switch (action.type) {        case UPDATE_TITLE_COLOR:            return {...state,title: {...state.title,color:action.color}};        case UPDATE_CONTENT_CONTENT:        return {...state,content: {...state.content,text:action.text}};                break;        default:            return state;        }}let store=createStore(reducer);render();let unsubscribe = store.subscribe(render);setTimeout(function () {    store.dispatch({
type:'UPDATE_TITLE_COLOR',color:'purple'}); unsubscribe(); store.dispatch({
type:'UPDATE_CONTENT_CONTENT',text:'新标题'});},2000);复制代码

转载地址:http://qpgfm.baihongyu.com/

你可能感兴趣的文章
关于Microsoft Speech SDK 中TTS的研究 [转]
查看>>
两个与后台有关的回调处理
查看>>
idhttp.post方式 调用datasnap rest 远程方法
查看>>
Gulp快速入门
查看>>
TClientDataSet的 fastscript封装
查看>>
有用的国外开源项目网址
查看>>
DataGridView 绑定DataTable方式编辑保存的bug?
查看>>
ComboBox 使用数据绑定时 Sorted 属性的bug
查看>>
BZOJ 3172 单词(ac自动机)
查看>>
具体数学第二版第四章习题(2)
查看>>
DotNetBar.7.0 Crack
查看>>
D3D中深度测试和Alpha混合的关系
查看>>
延时执行和取消延时执行
查看>>
关于线程安全
查看>>
使用Java自带的VisualVM监控远程主机JVM内存使用情况
查看>>
123——Appium Girls活动
查看>>
Linux系统CPU频率调整工具使用
查看>>
使用大于16TB的ext4文件系统
查看>>
jquery ajax cache的问题
查看>>
VIM 与 系统剪切版
查看>>