前端(九):redux使用实例

  开头先写一句理论:所谓状态机,是一种抽象的数据模型,是“事物发展的趋势”,其原理是事件驱动。广泛地讲,世界万物都是状态机。

一、状态机是一种抽象的数据模型

  在react中,props和state都可以用来传递数据。这里作一下区分。

  1.props

  props用于组件间的数据传递。其本身只是一个属性,不是一个状态机。

  从子组件的角度看,子组件无法擅自修改父组件通过属性传递的数据,因此具有单向数据流的特点。

  2.state

  state用于设置组件本身的状态。state用于用户数据交互、事件监听。

  当state数据发生改变时,该组件和state数据作用域内的子组件都会一层一层地重新渲染。

  3.state与props

  props传递state中的数据时,如果数据发生改变,子组件会被重新渲染。

  子组件可以通过调用父组件的方法来修改父组件传递过来的数据。

import React from ‘react‘import ReacDOM from ‘react-dom‘import { Button } from ‘antd-mobile‘

class SubCom extends React.Component{    constructor(props){        super(props);        this.state={ name: "Jan" }    }    render(){        // 将子组件数据传递给父组件        console.log("我被重新渲染了");        return <Button type=‘primary‘ onClick={()=>this.props.handleChange("name", this.state.name)}>点我</Button>    }}// 通过函数改变state状态修改父组件传递的值class App extends React.Component{    constructor(props){        super(props);        this.state = {            string: "我是一个button"        };        this.handleChange = this.handleChange.bind(this)    }    handleChange(key, val){        this.setState({            string: "我是一个蓝色的button",            key: val        })    };    render(){        console.log(this.state);        return <SubCom handleChange={ this.handleChange }/>    }}ReacDOM.render(    <App />,    document.getElementById("root"));

  4、state的局限性

  state作为单个组件的状态机,关注的只是单个组件内部。如果一个子组件需要修改一个父组件的state,那么父组件就需要将handleChange一级一级地传递给这个组件,并且要保证整个过程不会被其它状态或属性干扰。并且当父组件的state发生改变时,其到这个自组件的所有中间组件都要重新渲染,这显然不符合我们的需要。

  因此,在复杂的数据交互中,state就显得力不从心。这时,一种更为抽象的数据模型应运而生,那就是redux。

  5、redux插件

  redux、redux-thunk、react-redux一起解决了上述问题。

  redux-thunk、react-redux主要工作是建立异步状态机,并能够只重新渲染state状态涉及的子组件,而其它无关中间组件则不会重新渲染。

  redux代表着更为抽象的数据模型,它的主要内容有两个:一是打破组件内部this.state的孤立性,使得各层级的组件能够共用一个state;二是解耦,将一些公用的状态抽离成一个状态树,专门处理特定的数据。

  6、redux状态机与props、state的关系

  redux状态机是抽离的公用的state。

  和组件内的state一样,需要用props来传递,这种传递只有一层:整个app的最外层provider,以及被connect装饰的子组件。

  可以从子组件的props中获取redux状态机中的state数据。

二、使用实例

  一个用户注册、登录和修改个人信息的状态机。

// src/reducer.jsimport axios from ‘axios‘;import {getRedirectPath} from ‘../utils/userRedirect‘

const ERROR_MSG = ‘ERROR_MSG‘;const LOAD_COOKIE =  "LOAD_COOKIE";const AUTH_SUCCESS = "AUTH_SUCCESS";const CLEAR_COOKIE = "CLEAR_COOKIE";

// 获取用户登录信息const initState = {    msg: ‘‘,    user:‘‘,    type:‘‘,    redirectTo:‘‘};

export function user(state=initState, action) {    switch (action.type){        case ERROR_MSG:            return {...state, isAuth: false, msg: action.msg};        case LOAD_COOKIE:            return {...state, ...action.payload};        case AUTH_SUCCESS:            return {...state, ...action.payload, redirectTo: getRedirectPath(action.payload)}; // getRedirectPath是根据返回data中的用户类型返回相应url的处理函数        case CLEAR_COOKIE:            return {...initState, redirectTo:‘/login‘};  // 将登录信息清空,回到初始状态,并重定向到login        default:            return state;    }}

// 假如注册、登录和更新数据的action函数以及返回的状态都一样,可以把它们合并到一起。function authSuccess(data){    return {type: AUTH_SUCCESS, payload:data}}function errMsg(msg) {    return {type: ERROR_MSG, msg}}

// 注册时获取用户信息export function register({user, pwd, repeatPwd, type}) {    if(!user || !pwd || !type){        return errMsg("用户名和密码不能为空")    }    if(pwd !== repeatPwd){        return errMsg(‘密码和确认密码不一致‘)    }    return dispatch=>{        axios.post(‘/user/register‘, {user, pwd, type}).then(res=>{            if(res.status===200 && res.data.code===0){                dispatch(authSuccess(res.data.data))            }else {                dispatch(errMsg(res.data.msg))            }        })    }}// 登录时获取用户信息export function login({user, pwd}) {    if(!user || !pwd){        return errMsg("用户名密码必须输入")    }    return dispatch=>{        axios.post(‘/user/login‘, {user, pwd}).then(res=>{            if(res.status===200 && res.data.code===0){                // console.log(res.data.data);                dispatch(authSuccess(res.data.data))  // 将loginSuccess改成authSuccess            }else {                dispatch(errMsg(res.data.msg))            }        })    }}
// 更新数据export function update(data) {    return dispatch=>{        axios.post(‘user/update‘, data).then(res=>{            if(res.status===200 && res.data.code===0){                dispatch(authSuccess(res.data.data))            }else {                dispatch(errMsg(res.data.msg))            }        })    }}

// 读取cookieexport function loadCookie(data) {    return {type: LOAD_COOKIE, payload: data}}// 清除cookieexport function clearCookie() {    return { type: CLEAR_COOKIE }}
code===0){ // console.log(res.data.data); dispatch(authSuccess(res.data.data)) // 将loginSuccess改成authSuccess }else { dispatch(errMsg(res.data.msg)) } }) }}// 读取cookieexport function loadCookie(data) { return {type: LOAD_COOKIE, payload: data}}// 更新数据export function update(data) { return dispatch=>{ axios.post(‘user/update‘, data).then(res=>{ if(res.status===200 && res.data.code===0){ dispatch(authSuccess(res.data.data)) }else { dispatch(errMsg(res.data.msg)) } }) }}// 清除cookieexport function clearCookie() { return { type: CLEAR_COOKIE }}

  状态机的使用例子。这里没有server端。

import React from ‘react‘import ReacDOM from ‘react-dom‘import {createStore, applyMiddleware, compose } from ‘redux‘import thunk from ‘redux-thunk‘import { Provider, connect } from ‘react-redux‘

import {List, InputItem, WingBlank, WhiteSpace, Button, NavBar } from ‘antd-mobile‘import { login } from "./reducer";

const store = createStore(user, compose(    applyMiddleware(thunk),    window.devToolsExtension?window.devToolsExtension():f=>f));

@connect(state=>state, { login })class App extends React.Component{    constructor(props){        super(props);        this.state={            user: ‘‘,            pwd: ‘‘        };        this.handleChange = this.handleChange.bind(this);        this.handleLogin = this.handleLogin.bind(this);    }    handleChange(key, val){        this.setState({[key]: val})    }    handleLogin(){        this.props.login(this.state)    }    render(){        return (            <div>                <WingBlank>                    <NavBar mode="dark">登录页面</NavBar>                    <List>                        <WhiteSpace />                        <InputItem onChange={v=>this.handleChange(‘user‘, v)}>用户</InputItem>                        <WhiteSpace />                        <InputItem onChange={v=>this.handleChange(‘pwd‘, v)} type=‘passwd‘>密码</InputItem>           <WhiteSpace />                        <Button type=‘primary‘ onClick={this.handleLogin}>登录</Button>                    </List>                </WingBlank>            </div>        )    }

}

ReacDOM.render(    <Provider store={ store }>        <App />    </Provider>,    document.getElementById("root"));

原文地址:https://www.cnblogs.com/kuaizifeng/p/9417127.html

时间: 2024-10-12 15:23:32

前端(九):redux使用实例的相关文章

【Unity 3D】学习笔记二十九:游戏实例——简单小地图制作

任何的学习,光看不练是学不好的.所以这次就总结回顾下怎么制作MMROPG类游戏中的小地图.在MMROPG类游戏里,主角在游戏世界里走动时,一般在屏幕右上角都会有一个区域来显示当前游戏场景的小地图.主角在游戏世界里走动,小地图里代表着主角的小标记也会随之移动.那怎么实现咧? 首先需要确定两个贴图,第一个是右上角的小地图背景贴图,应该是从Y轴俯视向下截取主角所在的位置大地图.第二个就是主角的位置大贴图.在本例中,因为没有学习unity地图制作,所以地图用一个面对象代替,主角用立方体代替,使用GUI来

【前端构建】WebPack实例与前端性能优化

计划把微信的文章也搬一份上来. 这篇主要介绍一下我在玩Webpack过程中的心得.通过实例介绍WebPack的安装,插件使用及加载策略.感受构建工具给前端优化工作带来的便利. 壹 | Fisrt 曾几何时,我们是如上图的方式引入JS资源的,相信现在很少遇见了.近年来Web前端开发领域朝着规范开发的方向演进.体现在以下两点: MVC研发构架.多多益处(逻辑清晰,程序注重数据与表现分离,可读性强,利于规避和排查问题...) 构建工具层出不穷.多多益处(提升团队协作,以及工程运维,避免人工处理琐碎而重

HTML5 indexedDB前端本地存储数据库实例教程 (转载)

一.indexedDB为何替代了Web SQL Database? 跟小朋友的教育从来没有什么“赢在起跑线”这种说法一样,在前端领域,也不是哪来先出来哪个就在日后引领风骚的. HTML5 indexedDB和Web SQL Database都是本地数据库数据存储,Web SQL Database数据库要出来的更早,然并卵.从2010年11月18日W3C宣布舍弃Web SQL database草案开始,就已经注定Web SQL Database数据库是明日黄花. 未来一定是indexedDB的,从

一周一个小demo — 前端后台的交互实例

这一周呢,本K在大神的指导下,完成了一个利用ajax与php文件上传处理相结合的一个留言板功能的小实例,下面就让本K来带大家瞅瞅如何实现这一种功能. 一.界面概览 首先我们来看一下这个小demo的具体效果. 这个demo中,主要包括了三个步骤,也分别对应了三个功能,分别是注册,登录与留言板功能.而这三个功能基本都借助了前后台交互的几种技术,下面,本K就给大家分别展示一下这三个功能实现的代码. 二.功能实现 1.注册功能与登录功能 1.1 代码展示 1.1.1 注册功能 (1)前段部分 <!DOC

react+redux官方实例TODO从最简单的入门(6)-- 完结

通过实现了增-->删-->改-->查,对react结合redux的机制差不多已经了解,那么把剩下的功能一起完成吧 全选 1.声明状态,这个是全选状态 2.action约定 3.reducers,更新store 4.底层组件实现函数 5.上层组件数据传递 到这里全选的功能就实现了 显示action的数量和删除completed操作 整过过程一模一样 1. 2. 3. 4.(展示action数量的view) (删除completed的view) 放到Footer中 在上层父组件进行数据通信

C#与数据库访问技术总结(九)之实例

实例 更新记录 在本例子中,建立一个供用户输入学生学号和姓名的文本框和几个对应不同操作类型的更新信息按钮,当用户输入信息以后单击相应的按钮则执行相应的操作.在此实例中还将接触到服务器信息验证的相关知识. (1)新建名为UpdateTest的Windows Application应用程序,在默认的Forml.cs中添加2个Label控件,2个TextBox控件,3个Button控件,按表4.7所示设置这7个控件的属性. 表4.7控件属性 控件类型                    ID属性  

WCF入门(九)--WCF实例管理

这组由Windows通讯基础(WCF)结合一组消息(客户端请求)服务实例所采用的技术被称为实例管理.一个完全由三种类型实例激活支持WCF,它们如下所述. 1.每个调用服务 每次调用服务是Windows通讯基础的默认实例激活模式.当一个WCF服务配置为每个调用服务,一个CLR对象是时间跨度客户调用或请求进行创建. CLR代表公共语言运行库,并在WCF服务实例. 在每个调用服务,每一个客户端请求实现专用消耗相同的内存并且新的服务实例较少,相较于其他类型的实例激活.必需有InstanceContext

前端知识 | Redux的使用

什么是 Redux? Redux 是整个项目的状态管理中心,数据存储仓库,集中式的存储和管理所有的组件的状态,并且可以让组件的状态以一种可预测的方式变化. 什么情况下使用 Redux? Redux 主要作为一个状态树的存在,主要作用可以用来集中管理共享数据,如果你想取某个数据,你就直接从状态树(store)上拿,你修改数据,其他页面上从状态树上取到的数据也会发生改变(如果你用了 subscribe 监听函数或者使用了 react-redux 类似的库帮你监听,则其他页面取到的数据会自动更新),R

react+redux官方实例TODO从最简单的入门(3)-- 删

上一篇文章我们实现了增删改查中<增>这个功能 那么这一篇我们将实现第二个功能,删! 首先增加一个状态: actions中增加对应的约定 到reducer里面设置执行的函数(这里todo.id当然是等于action.id,所以返回false) 然后给子组件,增加这个方法 现在删除这个功能也实现了,这个不好演示,写到这一步,自己试一下就能完成了.