前端知识 Redux的使用
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端知识 Redux的使用相关的知识,希望对你有一定的参考价值。
参考技术A 什么是 Redux?Redux 是整个项目的状态管理中心,数据存储仓库,集中式的存储和管理所有的组件的状态,并且可以让组件的状态以一种可预测的方式变化。
什么情况下使用 Redux?
Redux 主要作为一个状态树的存在,主要作用可以用来集中管理共享数据,如果你想取某个数据,你就直接从状态树(store)上拿,你修改数据,其他页面上从状态树上取到的数据也会发生改变(如果你用了 subscribe 监听函数或者使用了 react-redux 类似的库帮你监听,则其他页面取到的数据会自动更新),Redux 不是必须的,它的使用场景是当你觉得项目内的组件通信太过于繁琐的时候使用,比如你有很多页面,很多组件,他们之间的通信很麻烦,或者说有些数据你需要保存起来供所有组件使用,这时候 Redux 的作用就体现出来了。
正如 Redux 的作者所说:
Flux 架构就像眼镜:您自会知道什么时候需要它。
核心概念
action
action 是一个对象,它包含了引起 store 状态变化的行为,他是将数据运输至 store 里的唯一手段。它通常包含一个 type 属性和一个需要传入 store 的数据,数据类型可以自定义。比如我们在做用户登录的时候经常需要将用户信息保存到 Redux,这时候 action 就可以是:
reducer
action 仅仅申明了我们想要改变 store 以及附带的数据,那么我们到底怎么去改变数据呢,比如说有一天用户的 money 变为2000,那么传入的 action 是:
那么这时候我们要怎么取改变 store 里面的值呢?这时候就要用到 reducer
简单来说,reducer 就是根据传入 actioon 类型描述如何去更改 store 中的状态。
store
单一状态树
action 描述了更改数据行为的发生,reducer 描述了如何去更改数据,那么我们数据还要有一个归宿就是 store,Redux 的核心就是一个 store 对象,它里面包含着我们所储存的所有状态,它类似一个物流中心,我们可以往里面存放数据,也可以从里面取出数据。它提供的方法包括:
1、getState() 获取当前的的 state 状态值
2、dispatch(action) 派发一个 action 行为更新 state
3、subscribe(listener) 注册一个监听器(当 state 跟新完了之后会自动执行)
这样这三个东西就串联在一起了。
store.dispatch(action) 用来接收不同的 action,表明要更新 state 的 type 类型以及更新需要的数据,再通过 reducer 函数计算到底怎么去更改 state,加还是减。
说了这么多,我们最后上个例子吧:
app.js
action.js
reducer.js
store.js
PS:这是最原始的 redux 使用方法,在实际开发中,通常还会结合 create-redux 等插件一起使用。
-END-
前端: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.js
import 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))
}
})
}
}
// 读取cookie
export function loadCookie(data) {
return {type: LOAD_COOKIE, payload: data}
}
// 清除cookie
export 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")
);
以上是关于前端知识 Redux的使用的主要内容,如果未能解决你的问题,请参考以下文章