【redux------状态管理库】

Redux学习

写在前面:此笔记是跟着尚硅谷课程视频学习

redux 是什么

  1. redux 是一个专门用于做状态管理的JS库(不是react 插件库)
  2. 可以用在react,angular,vue 等项目中,但基本与react配合使用
  3. 作用:集中式管理react 应用中多个组件共享的状态

redux 使用场景

  1. 某个组件的状态,需要让其他组件可以随时拿到(共享)
  2. 一个组件需要改变另一个组件的状态(通信)

redux 工作原理图

在这里插入图片描述

redux三个核心概念

从上面这个图我们可以发现包含四个部分的信息,第一个 React Components 表示是我们自己写的组件信息,第二个是Action Creators 将组件里的执行的操作封装成action对象,第三个是 Store 是调度者,将action 对象dispatch发布出来交给reducers调用,第四部分是 reducers ,reducers接收初始state 以及action ,调用完成产生新的state 状态 通知Store

三个核心概念

action

action 是一个js对象,是可以把应用数据传递到store 的唯一渠道,这个数据可以是用户输入,或者是从后端获取的数据。antion 包含两个属性,type 表示即将要执行的操作,多数情况下,需要用常量表示。如果是一个比较大的项目,建议单独写actions
一般情况下 通过dispatch()将action 传递到store

1.动作的对象
2.包含2个属性
   type:标识属性, 值为字符串, 唯一, 必要属性
   data:数据属性, 值类型任意, 可选属性
3.例子:{ type: 'ADD_STUDENT',data:{name: 'tom',age:18} }
或者
actions/ userInfo.js
// Action 创建函数,用于生成Action
export default setUserInfo=(params={})=>{
 return {
      type:"SET_USERINFO",
      payload: {userInfo:params}
  }
}
// 现在从后端发起一个请求,获取用户的基本信息res,
//目标是将获取的信息res 存储到store 容器中,那么这时候就需要 disoatch()方法
store.dispatch(serUserInfo(res??{}))

reducer

  1. 用于初始化状态、加工状态。初始化的时候(preViousState,action) preViousState是undefined ;加工状态时preViousState 是上一次的状态值
  2. 加工时,根据旧的state和action, 产生新的state的纯函数。
  3. 保持 reducer 纯净非常重要。永远不要在 reducer 里调用非纯函数或有执行副作用的操作(如 API 请求和路由跳转)。

一个简单的reducer 的例子

reducers/index.js

export default counter=(state = 0, action)=> {
  switch (action.type) {
  case 'INCREMENT':
    return state + 1
  case 'DECREMENT':
    return state - 1
  default:
    return state
  }
}
export default  information=(state={},action)=>{
   switch(action.type){
   case 'SET_USERINFO':
	    const {userinfo={}} = actiom.payload
	    return{
	    ...state,
	    userInfo
	    }
    default:
       state
   }
}

store

1.将state、action、reducer联系在一起的对象
2.如何得到此对象?
	1)import {createStore} from 'redux'
	2)import reducer from './reducers'
	3)const store = createStore(reducer)
3.此对象的功能?
	1)getState(): 得到state
	2)dispatch(action): 分发action, 触发reducer调用, 产生新的state
	3)subscribe(listener): 注册监听, 当产生了新的state时, 自动调用

每当我们在 store 上 dispatch 一个 action,store 内的数据就会相应地发生变化。

React Component 中如何使用 store 中的数据

可以直接在 React 中使用 Redux:在最外层容器组件中初始化 store,然后将state 上的属性作为 props 层层传递下去。

	
class App extends Component{

  componentWillMount(){
    store.subscribe((state)=>this.setState(state))
  }

  render(){
    return <Comp state={this.state}
                 onIncrease={()=>store.dispatch(actions.increase())}
                 onDecrease={()=>store.dispatch(actions.decrease())}
    />
  }
}

但这并不是最佳的方式。最佳的方式是使用 react-redux 提供的 Provider 和 connect 方法。

使用 react-redux
首先在最外层容器中,把所有内容包裹在 Provider 组件中,将之前创建的 store 作为prop 传给 Provider。

import React ,{Component} from 'react'
import store from '@/store'
import {Provider} from 'react-redux'

class App extends Component {

  render() {
    return (
      <Provider store={store}>
        {this.props.children}
      </Provider>
    );
  }
}

export default App;

Provider 内的任何一个组件,如果想使用store 内的数据,那么这个组件必须被connect 过。
connect 对象真正的将React 组件与store 连接起来

connect 详解

connect 包括四个参数

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])

mapStateToProps(state, ownProps) : stateProps

允许我们将store 中的数据作为props 绑定到组件上

 const mapStateToProps = (state) => ({
  todoList : state.todoList
 })

在需要使用store 的组件中 通过上述代码就可以通过 this.props.todoList 获取数据。

函数的第二个参数 ownProps,就是当在名称为 Mydata组件中使用store 数据时,这个 owmProps 是 Mydata 自己的 props。有的时候,ownProps 也会对其产生影响。比如,当你在 store 中维护了一个用户列表,而你的组件 Mydata 只关心一个用户(通过 props 中的 userId 体现)。

// state 是 {userList: [{id: 0, name: '王二'},{id: 1, name: '李四'}]}
// 在Mydata 组件中只关心第一个用户,
//通过自己的props提供的userId 查询state里userList 的数据
const mapStateToProps = (state, ownProps) => {
  return {
    user: _.find(state.userList, {id: ownProps.userId})
  }
}

当 state 变化,或者 ownProps 变化的时候,mapStateToProps 都会被调用,计算出一个新的stateProps,(在与 ownProps merge 后)更新给 Mydata。

这就是将 Redux store 中的数据连接到组件的基本方式。

mapDispatchToProps(dispatch, ownProps): dispatchProps

mapDispatchToProps 是将action 作为props 绑定到Mydata 组件上,

const mapDispatchToProps = {
  addTodo,
  delTodo
}

将addTodo与 delTodo 函数作为props 绑定到组件上,可以通过 this.props.addTodo()操作store 中的数据。

export const addTodo = (data) => {
    return dispatch => {
      //告诉reducer类型,reducer根据不同的类型做不同的操作
      dispatch({ type: 'ADD_TODO', data })
    }
  }
 /**
 通过调用 this.props.addTod() 返回一个触发dispatch的action对象
 只要调用该方法就会触发dispatch 方法,
 diapatch 可以根据旧的数据和新的state 更新state ,存储在store里边
*/

[mergeProps(stateProps, dispatchProps, ownProps): props]
之前说过,不管是 stateProps 还是 dispatchProps,都需要和 ownProps merge 之后才会被赋给 Mydata。connect 的第三个参数就是用来做这件事。通常情况下,你可以不传这个参数,connect 就会使用 Object.assign 替代该方法。

其他

最后还有一个 options 选项,比较简单,基本上也不大会用到(尤其是你遵循了其他的一些 React 的「最佳实践」的时候),本文就略过了。希望了解的同学可以直接看文档

举例说明

首先创建一个新 todoList 的项目(此例子来自这里

// 创建项目
create-react-app my_redux
// 安装 redux
npm install --save redux react-redux redux-thunk

第一步 创建store 容器
store/index.js

// applyMiddleware: redux通过该函数来使用中间件
// createStore: 用于创建store实例
import {createStore,applyMiddleware} from 'redux'
//thunk中间件可以支持异步action
import thunk from 'redux-thunk'
import reducer from './reducer'
const store = createStore(reducer,applyMiddleware(thunk))
export default store

第二步 action
store/action.js

export const addTodo = (data) => {
    return dispatch => {
      //告诉reducer类型,reducer根据不同的类型做不同的操作
      dispatch({ type: 'ADD_TODO', data })
    }
  }
  export const delTodo = (index) => {
    return dispatch => {
      dispatch({type : 'DEL_TODO',index})
    }
  }

第三步 reducer
store/reducer.js

//创建唯一的初始化state,如果初始化元素比较多可以单独创建state.js方便管理
const initState = {
    todoList : ['早上五点钟起床','锻炼身体一小时','做饭吃饭']
  }
  
  //编写reducer根据不同的类型做不同的操作修改state
  const reducer = (state = initState,action) =>{
    //state是只读,所以每次修改都返回一个新的state
    let newState = JSON.parse(JSON.stringify(state))
    switch(action.type){
      case 'ADD_TODO':
        newState.todoList.push(action.data);
        return newState;
      case 'DEL_TODO':
        newState.todoList.splice(action.index,1);
        return newState;
      default:
        return newState;
    }
  }
  
  export default reducer

第四步 app.js

import React, { Component } from 'react'
// connect方法的作用:将额外的props传递给组件,并返回新的组件,组件在该过程中不会受到影响
import { connect } from 'react-redux'
// 引入action
import {addTodo,delTodo} from './store/action'
class App extends Component {
  state = {
    value : ''
  }
  changeValue = (e) =>{
    this.setState({
      value : e.target.value,
    })
  }
  addTodoFn = () =>{
    //触发addTodo添加备忘的action
    this.props.addTodo(this.state.value)
    this.setState({
      value :''
    })
  }
  delTodoFn = (index) =>{
    //触发delTodo删除备忘的action
    this.props.delTodo(index)
  }
  render() {
    return (
      <div>
        <ol>
          {this.props.todoList.map((item,index)=>(
            <li key={index} onClick={this.delTodoFn.bind(this,index)}>{item}</li>
          ))}
        </ol>
        <input type="text" value={this.state.value} onChange={this.changeValue}/>
        <button onClick={this.addTodoFn}>添加</button>
      </div>
    )
  }
}
// mapStateToProps:将state映射到组件的props中
// const mapStateToProps = (state) => ({
//   todoList : state.todoList
// })
// mapDispatchToProps:将action里的dispatch映射到组件的props中
const mapDispatchToProps = {
  addTodo,
  delTodo
}

export default connect(state=>({
  todoList : state.todoList
}),mapDispatchToProps)(App)

最后一步,index.js 需要用provider 包裹起来

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
 引入创建好的store实例
import store from './store'
// Provider是react-redux两个核心工具之一,作用:将store传递到每个项目中的组件中
import {Provider} from 'react-redux'

ReactDOM.render(
  <Provider store={store}>
    {/* 将store作为prop传入,即可使应用中的所有组件使用store */}
    <App />
  </Provider>,
  document.getElementById('root')
);

效果如下
在这里插入图片描述

参考:1. https://blog.csdn.net/weixin_34008805/article/details/90628145?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-90628145-blog-120002284.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-90628145-blog-120002284.pc_relevant_aa&utm_relevant_index=2
2. https://juejin.cn/post/6953866924065292318#heading-6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值