redux-基础

1.redux是什么?

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

2.什么情况下需要使用redux

  • 某个组件的状态,需要让其他组件可以随时拿到(共享)
  • 一个组件需要改变另一个组件的状态(通信)
  • 总体原则:能不用就不用,如果不用比较吃力才考虑使用

3.redux的工作流程

在这里插入图片描述

4.redux的三个核心概念

4.1action

  • 动作的对象
  • 包含两个属性
    • type:标识属性,值为字符串,唯一,必要属性
    • data:数据属性,值为任意类型,可选属性
  • 例如:{type:‘ADD_STUDENT’,data:{name:‘tom’,age:18} }

4.2reducer

  • 用于初始化状态,加工状态
  • 加工时,根据旧的state和acticon,产生新的state的纯函数

4.3store

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

5.案例-非redux版本

import React, {
    
     Component } from 'react'
import ReactDOM from 'react-dom';
import {
    
     BrowserRouter, NavLink, Route, Switch, Redirect, withRouter } from 'react-router-dom';

class App extends React.Component {
    
    
  state = {
    
    
    msg: '这里是App组件',
    count: 0
  }
  increase = () => {
    
    
    let {
    
     value } = this.selectDOM;
    let {
    
     count } = this.state;
    count += Number(value);
    this.setState({
    
    
      count
    })
  }
  decrease = () => {
    
    
    let {
    
     value } = this.selectDOM;
    let {
    
     count } = this.state;
    count -= Number(value);
    this.setState({
    
    
      count
    })
  }
  oddIncrease = () => {
    
    
    let {
    
     value } = this.selectDOM;
    let {
    
     count } = this.state;
    if (count % 2 == 0) {
    
    
      count += Number(value);
      this.setState({
    
    
        count
      })
    }
  }
  asyncIncrease = () => {
    
    
    let {
    
     value } = this.selectDOM;
    let {
    
     count } = this.state;
    setTimeout(() => {
    
    
      count += Number(value);
      this.setState({
    
    
        count
      })
    }, 1000);
  }
  render() {
    
    
    return (
      <div className="app">
        <h1>当前求和为{
    
    this.state.count}</h1>
        <select ref={
    
    (currentNode) => {
    
    
          this.selectDOM = currentNode;
        }}>
          <option value="1">1</option>
          <option value="2">2</option>
          <option value="3">3</option>
        </select>
        <button onClick={
    
    this.increase}>+</button>
        <button onClick={
    
    this.decrease}>-</button>
        <button onClick={
    
    this.oddIncrease}>求和为奇数加</button>
        <button onClick={
    
    this.asyncIncrease}>异步+</button>
      </div>
    )
  }
}

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>, document.querySelector('#root'));

6.redux-精简版

  • 笔记
    • 去除组件自身需要让redux管理的状态
    • .src下建立
      • redux
        • store.js
        • reducer.js
    • store.js
      • 引入redux中createStore函数,创建一个store
      • createStore调用时要传入一个为其服务的reducer
      • 暴露store对象
    • reducer.js
      • reducer本质是一个函数,接受prevState,action,返回加工后的状态
      • reducer有两个作用:初始化状态/加工状态
      • reducer第一次被调用的时候,是store自动触发的,传递prevState是undefined/传递的action:{type:@@redux/INITw.a.v.g.2.j}
    • 在index.js中检测store中状态的改变,一旦发生改变就重新渲染组件
      • redux值负责管理状态,至于状态的改变驱动着页面的展示,就需要自己完成了
  • reducer.js
//创建一个为store服务的Reducer;Reducer的本质就是一个函数
//storeReducer函数会接收到两个参数,分别为之前的对象(prevState)和动作对象(action)

let initState = 0;//初始化状态
function storeReducer(prevState = initState, action) {
    
    
  // console.log(prevState, action);
  // 从action对象中获取:type,data
  let {
    
     type, data } = action;
  // 根据type决定如何加工数据
  switch (type) {
    
    
    // 加
    case 'increase':
      return prevState += data;
    // 减
    case 'decrease':
      return prevState -= data;
    // 初始化
    default:
      return prevState
  }
}

export default storeReducer;
  • store.js
// 该文件专门用于暴露一个store对象,整个应用只有一个store对象

//引入createStore,专门用于创建redux中最核心的store对象
import {
    
     createStore } from 'redux';
// 引入为组件服务的reducer
import storeReducer from './reducer';

let store = createStore(storeReducer);

//暴露store对象
export default store;
  • App.jsx
import React from 'react';
import './index.scss';
import store from './redux/store.js';

class App extends React.Component {
    
    
  state = {
    
    
    msg: '这里是App组件',
    count: 996
  }
  increase = () => {
    
    
    let {
    
     value } = this.selectDOM;
    // 通知redux+value
    store.dispatch({
    
    
      type: 'increase',
      data: Number(value)
    })
  }
  decrease = () => {
    
    
    let {
    
     value } = this.selectDOM;
    // 通知redux-value
    store.dispatch({
    
    
      type: 'decrease',
      data: Number(value)
    })
  }
  oddIncrease = () => {
    
    
    let count = store.getState();
    if (count % 2 == 0) {
    
    
      this.increase();
    }
  }
  asyncIncrease = () => {
    
    
    setTimeout(() => {
    
    
      this.increase();
    }, 1000);
  }
  render() {
    
    
    return (
      <div className="app">
        <h1>当前求和为{
    
    store.getState()}</h1>
        <select ref={
    
    (currentNode) => {
    
    
          this.selectDOM = currentNode;
        }}>
          <option value="1">1</option>
          <option value="2">2</option>
          <option value="3">3</option>
        </select>
        <button onClick={
    
    this.increase}>+</button>
        <button onClick={
    
    this.decrease}>-</button>
        <button onClick={
    
    this.oddIncrease}>求和为偶数加</button>
        <button onClick={
    
    this.asyncIncrease}>异步+</button>
      </div>
    )
  }

  // componentDidMount() {//这样写有一个缺点,就是我要在每个组件中都写一次,十分的麻烦
  //   // 检测redux中状态的变化,只要发生变化就调用render
  //   store.subscribe(() => {
    
    
  //     this.setState({})
  //     // this.forceUpdate()
  //   })
  // }
}

export default App;
  • index.js
import React from 'react'
import ReactDOM from 'react-dom';
import {
    
     BrowserRouter } from 'react-router-dom';
import App from './App.jsx'
import './normalize.css';
import store from './redux/store.js';

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>, document.querySelector('#root'));

store.subscribe(() => {
    
    //检测redux中状态的变化,只要发生变化就调用render
  ReactDOM.render(
    <BrowserRouter>
      <App />
    </BrowserRouter>, document.querySelector('#root'));
})

7.redux-完整版

  • 新增文件
    • action.js 专门用于创建action对象
    • constant.js 防止容易写错的type值
  • constant.js
// 该模块是用于定义action对象中type类型常量值
export const INCREASE = 'increase';
export const DECREASE = 'decrease';
  • action.js
//该文件专门为组件生成action对象;目的只有一个便于管理的同时,防止程序员单词写错

import {
    
     INCREASE, DECREASE } from './constant.js';//引入常量对象

export function createIncrease(data) {
    
    
  return {
    
     type: INCREASE, data: data }
}

export function createDecrease(data) {
    
    
  return {
    
     type: DECREASE, data: data }
}
  • reducer.js
//创建一个为store服务的Reducer;Reducer的本质就是一个函数
//storeReducer函数会接收到两个参数,分别为之前的对象(prevState)和动作对象(action)
import {
    
     INCREASE, DECREASE } from './constant.js';//引入常量对象

let initState = 0;//初始化状态
function storeReducer(prevState = initState, action) {
    
    
  // console.log(prevState, action);
  // 从action对象中获取:type,data
  let {
    
     type, data } = action;
  // 根据type决定如何加工数据
  switch (type) {
    
    
    // 加
    case INCREASE:
      return prevState += data;
    // 减
    case DECREASE:
      return prevState -= data;
    // 初始化
    default:
      return prevState
  }
}

export default storeReducer;
  • store.js
// 该文件专门用于暴露一个store对象,整个应用只有一个store对象

//引入createStore,专门用于创建redux中最核心的store对象
import {
    
     createStore } from 'redux';
// 引入为组件服务的reducer
import storeReducer from './reducer';

let store = createStore(storeReducer);

//暴露store对象
export default store;
  • App.jsx
import React from 'react';
import './index.scss';
// 引入store,用于获取redux中保存的状态
import store from './redux/store.js';
// 引入action,专门用于创建action对象
import {
    
     createIncrease, createDecrease } from './redux/action.js';


class App extends React.Component {
    
    
  state = {
    
    
    msg: '这里是App组件'
  }
  increase = () => {
    
    
    let {
    
     value } = this.selectDOM;
    store.dispatch(createIncrease(Number(value)))
  }
  decrease = () => {
    
    
    let {
    
     value } = this.selectDOM;
    store.dispatch(createDecrease(Number(value)))
  }
  oddIncrease = () => {
    
    
    let count = store.getState();
    if (count % 2 !== 0) {
    
    //奇数+
      this.increase();
    }
  }
  asyncIncrease = () => {
    
    
    setTimeout(() => {
    
    
      this.increase();
    }, 1000);
  }
  render() {
    
    
    return (
      <div className="app">
        <h1>当前求和为{
    
    store.getState()}</h1>
        <select ref={
    
    (currentNode) => {
    
    
          this.selectDOM = currentNode;
        }}>
          <option value="1">1</option>
          <option value="2">2</option>
          <option value="3">3</option>
        </select>
        <button onClick={
    
    this.increase}>+</button>
        <button onClick={
    
    this.decrease}>-</button>
        <button onClick={
    
    this.oddIncrease}>求和为奇数加</button>
        <button onClick={
    
    this.asyncIncrease}>异步+</button>
      </div>
    )
  }
}

export default App;
  • index.js
import React from 'react'
import ReactDOM from 'react-dom';
import {
    
     BrowserRouter } from 'react-router-dom';
import App from './App.jsx'
import './normalize.css';
import store from './redux/store.js';

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>, document.querySelector('#root'));

store.subscribe(() => {
    
    //监听store中状态的改变,执行函数
  ReactDOM.render(
    <BrowserRouter>
      <App />
    </BrowserRouter>, document.querySelector('#root'));
})

8.redux-异步版

  • 明确:延yi便迟的动作不想交给组件自身,想交给action
  • 何时需要action:想要对状态进行操作,但是具体的数据靠异步任务返回
  • 具体编码
    • cnpm install redux-thunk ,并配置在store中
    • 创建action的函数不再返回一般对象 ,而是一个函数,该函数中写异步任务
    • 异步任务又结果之后,分发给一个同步的action去真正操作数据
  • 备注:异步action不是必须要写的,完全可以自己等待异步任务的结果再去分发同步action
  • constant.js
// 该模块是用于定义action对象中type类型常量值
export const INCREASE = 'increase';
export const DECREASE = 'decrease';
  • action.js
//该文件专门为组件生成action对象;目的只有一个便于管理的同时,防止程序员单词写错
import {
    
     INCREASE, DECREASE } from './constant.js';//引入常量对象

// 同步action,就是指action的值为object类型的一般对象
export function createIncrease(data) {
    
    
  return {
    
     type: INCREASE, data: data }
}

export function createDecrease(data) {
    
    
  return {
    
     type: DECREASE, data: data }
}

// 异步action,就是指action的值为函数,异步action一般都会调用同步action,异步action不是必须要用的
export function createIncreaseAsyncAction(data, speed) {
    
    
  return (dispatch) => {
    
    
    setTimeout(() => {
    
    
      dispatch(createIncrease(data))
    }, speed);
  }
}
  • reducer.js
//创建一个为store服务的Reducer;Reducer的本质就是一个函数
//storeReducer函数会接收到两个参数,分别为之前的对象(prevState)和动作对象(action)

import {
    
     INCREASE, DECREASE } from './constant.js';//引入常量对象

let initState = 0;//初始化状态
function storeReducer(prevState = initState, action) {
    
    
  // console.log(prevState, action);
  // 从action对象中获取:type,data
  let {
    
     type, data } = action;
  // 根据type决定如何加工数据
  switch (type) {
    
    
    // 加
    case INCREASE:
      return prevState += data;
    // 减
    case DECREASE:
      return prevState -= data;
    // 初始化
    default:
      return prevState
  }
}

export default storeReducer;
  • store.js
// 该文件专门用于暴露一个store对象,整个应用只有一个store对象

//引入createStore,专门用于创建redux中最核心的store对象
import {
    
     createStore, applyMiddleware } from 'redux';
// 引入为组件服务的reducer
import storeReducer from './reducer';
//引入redux-thunk,用于支持异步
import thunk from 'redux-thunk';

let store = createStore(storeReducer, applyMiddleware(thunk));

//暴露store对象
export default store;
  • App.jsx
import React from 'react';
import './index.scss';
// 引入store,用于获取redux中保存的状态
import store from './redux/store.js';
// 引入action,专门用于创建action对象
import {
    
     createIncrease, createDecrease, createIncreaseAsyncAction } from './redux/action.js';


class App extends React.Component {
    
    
  state = {
    
    
    msg: '这里是App组件'
  }
  increase = () => {
    
    
    let {
    
     value } = this.selectDOM;
    store.dispatch(createIncrease(Number(value)))
  }
  decrease = () => {
    
    
    let {
    
     value } = this.selectDOM;
    store.dispatch(createDecrease(Number(value)))
  }
  oddIncrease = () => {
    
    
    let count = store.getState();
    if (count % 2 !== 0) {
    
    //奇数+
      this.increase();
    }
  }
  asyncIncrease = () => {
    
    
    // setTimeout(() => {
    
    
    let {
    
     value } = this.selectDOM;
    store.dispatch(createIncreaseAsyncAction(Number(value), 1000))
    // }, 1000);
  }
  render() {
    
    
    return (
      <div className="app">
        <h1>当前求和为{
    
    store.getState()}</h1>
        <select ref={
    
    (currentNode) => {
    
    
          this.selectDOM = currentNode;
        }}>
          <option value="1">1</option>
          <option value="2">2</option>
          <option value="3">3</option>
        </select>
        <button onClick={
    
    this.increase}>+</button>
        <button onClick={
    
    this.decrease}>-</button>
        <button onClick={
    
    this.oddIncrease}>求和为奇数加</button>
        <button onClick={
    
    this.asyncIncrease}>异步+</button>
      </div>
    )
  }
}

export default App;
  • index.js
import React from 'react'
import ReactDOM from 'react-dom';
import {
    
     BrowserRouter } from 'react-router-dom';
import App from './App.jsx'
import './normalize.css';
import store from './redux/store.js';

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>, document.querySelector('#root'));

store.subscribe(() => {
    
    //监听store中状态的改变,执行函数
  ReactDOM.render(
    <BrowserRouter>
      <App />
    </BrowserRouter>, document.querySelector('#root'));
})

猜你喜欢

转载自blog.csdn.net/big_sun_962464/article/details/113087172