React(五)——Redux

目录

1.知识点

2.状态(数据)管理

3.Redux——核心概念

3.1state 对象

3.1.1state 是只读的

3.1.2通过纯函数修改 state

3.2Reducer 函数

3.3action 对象

3.4Store 对象

3.4.1Redux.createStore 方法

3.4.2getState() 方法

3.4.3dispatch() 方法

3.4.4action 创建函数

3.4.5subscribe() 方法

4.Redux——工作流

5.Redux——Reducers 分拆与融合

5.1combineReducers 方法

6.react-redux

6.1安装

6.2 Provider 组件

6.3connect 方法

6.3.1注入 state 到 props

7.Redux DevTools extension

8.异步 action

8.1package.json 配置

8.2./src/setupProxy.js 配置

9.Middleware

9.1redux.applyMiddleware

10.redux-chunk

10.1安装


1.知识点

  • 状态管理器
  • state 对象
  • reducer 纯函数
  • store 对象
  • action 对象
  • combineReducers 方法
  • react-redux
  • provider 组件
  • connect 方法
  • Redux DevTools extension 工具
  • 中间件 - middleware
  • redux-chunk

2.状态(数据)管理

前端应用越来越复杂,要管理和维护的数据也越来越多,为了有效的管理和维护应用中的各种数据,我们必须有一种强大而有效的数据管理机制,也称为状态管理机制,Redux 就是解决该问题的

3.Redux——核心概念

Redux 是一个独立的 JavaScript 状态管理库,与非 React 内容之一

https://www.bootcdn.cn/redux/

理解 Redux 核心几个概念与它们之间的关系

  • state

  • reducer

  • store

  • action

3.1state 对象

通常我们会把应用中的数据存储到一个对象树(Object Tree) 中进行统一管理,我们把这个对象树称为:state

3.1.1state 是只读的

这里需要注意的是,为了保证数据状态的可维护和测试,不推荐直接修改 state 中的原数据

3.1.2通过纯函数修改 state

什么是纯函数?

纯函数

  1. 相同的输入永远返回相同的输出

  2. 不修改函数的输入值

  3. 不依赖外部环境状态

  4. 无任何副作用

使用纯函数的好处

  1. 便于测试

  2. 有利重构

3.2Reducer 函数

function todo(state, action) {
  switch(action.type) {
    case 'ADD':
      return [...state, action.payload];
      break;
    case 'REMOVE':
      return state.filter(v=>v!==action.payload);
      break;
    default:
      return state;
	}
}

上面的 todo 函数就是 Reducer 函数

  1. 第一个参数是原 state 对象

  2. Reducer 函数不能修改原 state,而应该返回一个新的 state

  3. 第二参数是一个 action 对象,包含要执行的操作和数据

  4. 如果没有操作匹配,则返回原 state 对象

3.3action 对象

我们对 state 的修改是通过 reducer 纯函数来进行的,同时通过传入的 action 来执行具体的操作,action 是一个对象

  • type 属性 : 表示要进行操作的动作类型,增删改查……

  • payload属性 : 操作 state 的同时传入的数据

但是这里需要注意的是,我们不直接去调用 Reducer 函数,而是通过 Store 对象提供的 dispatch 方法来调用

3.4Store 对象

为了对 stateReduceraction 进行统一管理和维护,我们需要创建一个 Store 对象

3.4.1Redux.createStore 方法

let store = Redux.createStore((state, action) => {
  // ...
}, []);

todo

用户操作数据的 reducer 函数

[]

初始化的 state

我们也可以使用 es6 的函数参数默认值来对 state 进行初始化

let store = Redux.createStore( (state = [], action) => {
  // ...
} )

3.4.2getState() 方法

通过 getState 方法,可以获取 Store 中的 state

store.getState();

3.4.3dispatch() 方法

通过 dispatch 方法,可以提交更改

store.dispatch({
  type: 'ADD',
  payload: 'MT'
})

3.4.4action 创建函数

action 是一个对象,用来在 dispatch 的时候传递动作和数据,我们在实际业务中可能会中许多不同的地方进行同样的操作,这个时候,我们可以创建一个函数用来生成(返回)action

function add(payload) {
  return {
    type: 'ADD',
    payload
  }
}

store.dispatch(add('MT'));
store.dispatch(add('Reci'));
...

3.4.5subscribe() 方法

可以通过 subscribe 方法注册监听器(类似事件),每次 dispatch action 的时候都会执行监听函数,该方法返回一个函数,通过该函数可以取消当前监听器

let unsubscribe = sotre.subscribe(function() {
  console.log(store.getState());
});
unsubscribe();

4.Redux——工作流

5.Redux——Reducers 分拆与融合

当一个应用比较复杂的时候,状态数据也会比较多,如果所有状态都是通过一个 Reducer 来进行修改的话,那么这个 Reducer 就会变得特别复杂。这个时候,我们就会对这个 Reducer 进行必要的拆分

let datas = {
  user: {},
  items: []
  cart: []
}

我们把上面的 usersitemscart 进行分拆

// user reducer
function user(state = {}, action) {
  // ...
}
// items reducer
function items(state = [], action) {
  // ...
}
// cart reducer
function cart(state = [], action) {
  // ...
}

5.1combineReducers 方法

该方法的作用是可以把多个 reducer 函数合并成一个 reducer

let reducers = Redux.combineReducers({
  user,
  items,
  cart
});

let store = createStore(reducers);

6.react-redux

再次强调的是,reduxreact 并没有直接关系,它是一个独立的 JavaScript 状态管理库,如果我们希望中 React 中使用 Redux,需要先安装 react-redux

6.1安装

npm i -S redux react-redux

// ./store/reducer/user.js
let user = {
    id: 0,
    username: ''
};

export default (state = user, action) => {
    switch (action.type) {
        default:
            return state;
    }
}
// ./store/reducer/users.js
let users = [{
    id: 1,
    username: 'baoge',
    password: '123'
},
{
    id: 2,
    username: 'MT',
    password: '123'
},
{
    id: 3,
    username: 'dahai',
    password: '123'
},
{
    id: 4,
    username: 'zMouse',
    password: '123'
}];

export default (state = users, action) => {
    switch (action.type) {
        default:
            return state;
    }
}
// ./store/reducer/items.js
let items = [
    {
        id: 1,
        name: 'iPhone XR',
        price: 542500
    },
    {
        id: 2,
        name: 'Apple iPad Air 3',
        price: 377700
    },
    {
        id: 3,
        name: 'Macbook Pro 15.4',
        price: 1949900
    },
    {
        id: 4,
        name: 'Apple iMac',
        price: 1629900
    },
    {
        id: 5,
        name: 'Apple Magic Mouse',
        price: 72900
    },
    {
        id: 6,
        name: 'Apple Watch Series 4',
        price: 599900
    }
];

export default (state = items, action) => {
    switch (action.type) {
        default:
            return state;
    }
}
// ./store/reducer/cart.js
export default (state = [], action) => {
    switch (action.type) {
        default:
            return state;
    }
}
// ./store/index.js
import {createStore, combineReducers} from 'redux';

import user from './reducer/user';
import users from './reducer/users';
import items from './reducer/items';
import cart from './reducer/cart';

let reducers = combineReducers({
    user,
    users,
    items,
    cart
});

const store = createStore(reducers);

export default store;

6.2 Provider 组件

想在 React 中使用 Redux ,还需要通过 react-redux 提供的 Provider 容器组件把 store 注入到应用中

// index.js
import {Provider} from 'react-redux';
import store from './store';

ReactDOM.render(
    <Provider store={store}>
        <Router>
            <App />
        </Router>
    </Provider>, 
    document.getElementById('root')
);

6.3connect 方法

有了 connect 方法,我们不需要通过 props 一层层的进行传递, 类似路由中的 withRouter ,我们只需要在用到 store 的组件中,通过 react-redux 提供的 connect 方法,把 store 注入到组件的 props 中就可以使用了

import {connect} from 'react-redux';
​
class Main extends React.Component {
  render() {
    console.log(this.props);
  }
}
​
export default connect()(Main);

默认情况下,connect 会自动注入 dispatch 方法

6.3.1注入 stateprops

export default connect( state => {
  return {
    items: state.items
  }
} )(Main);

connect 方法的第一个参数是一个函数

  • 该函数的第一个参数就是 store 中的 state : store.getState()
  • 该函数的返回值将被解构赋值给 props : this.props.items

7.Redux DevTools extension

为了能够更加方便的对 redux 数据进行观测和管理,我们可以使用 Redux DevTools extension 这个浏览器扩展插件

https://github.com/zalmoxisus/redux-devtools-extension

const store = createStore(
    reducers,
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);

打开浏览器开发者工具面板 -> redux

8.异步 action

许多时候,我们的数据是需要和后端进行通信的,而且中开发模式下,很容易就会出现跨域请求的问题,好在 create-react-app 中内置了一个基于 node 的后端代理服务,我们只需要少量的配置就可以实现跨域

8.1package.json 配置

相对比较的简单的后端 URL 接口,我们可以直接中 package.json 文件中进行配置

// 后端接口
http://localhost:7777/api/items
// http://localhost:3000
{
  ...
  //
  "proxy": "http://localhost:7777"
}
axios({
  url: '/api/items'
});

8.2./src/setupProxy.js 配置

针对相对复杂的情况,可以有更多的配置

npm i -S http-proxy-middleware
// setupProxy.js
const proxy = require('http-proxy-middleware');
​
module.exports = function(app) {
    app.use(
        proxy('/api', {
            target: 'http://localhost:7777/',
            pathRewrite: {
                '^/api': ''
            }
        })
    );
};

其它代码同上

9.Middleware

默认情况下,dispatch 是同步的,我们需要用到一些中间件来处理

const logger = store => next => action => {
  console.group(action.type)
  console.info('dispatching', action)
  let result = next(action)
  console.log('next state', store.getState())
  console.groupEnd(action.type)
  return result
}

9.1redux.applyMiddleware

通过 applyMiddleware 方法,我们可以给 store 注册多个中间件

注意:devTools 的使用需要修改一下配置

npm i -D redux-devtools-extension
...
import { composeWithDevTools } from 'redux-devtools-extension';
...
const store = createStore( 
  reducres, 
  composeWithDevTools(
    applyMiddleware( logger )
  )
)

10.redux-chunk

这是一个把同步 dispatch 变成异步 dispatch 的中间件

10.1安装

npm i -S redux-thunk

import {createStore, combineReducers, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';

import user from './reducer/user';
import items from './reducer/items';
import cart from './reducer/cart';

let reducers = combineReducers({
    user,
    items,
    cart
});

const store = createStore(
    reducers,
    composeWithDevTools(applyMiddleware(
        thunk
    ))
);
发布了95 篇原创文章 · 获赞 115 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_34569497/article/details/105210573
今日推荐