1.核心概念

  • 1.什么是Redux?

    • Redux是一个管理状态(数据)的容器,提供了可预测的状态管理
  • 2.什么是可预测的状态管理?
    • 数据 在什么时候, 因为什么, 发生了什么改变,都是可以控制和追踪的,我们就称之为预测的状态管理
  • 3.为什么要使用Redux?
    • React是通过数据驱动界面更新的,React负责更新界面, 而我们负责管理数据
    • 默认情况下我们可以在每个组件中管理自己的状态, 但是现在前端应用程序已经变得越来越复杂
    • 状态之间可能存在依赖关系(父子、共享等),一个状态的变化会引起另一个状态的变化
    • 所以当应用程序复杂的时候, 状态在什么时候改变,因为什么改变,发生了什么改变,就会变得非常难以控制和追踪
    • 所以当应用程序复杂的时候,我们想很好的管理、维护、追踪、控制状态时, 我们就需要使用Redux
  • 4.Redux核心理念
    • 通过 store 来 保存数据
    • 通过 action 来 修改数据
    • 通过 reducer 来 关联 store 和 action

2.三大原则

  • 1.Redux三大原则

    • 单一数据源

      • 整个应用程序的state只存储在一个 store 中
      • Redux并没有强制让我们不能创建多个Store,但是那样做并不利于数据的维护
      • 单一的数据源可以让整个应用程序的state变得方便维护、追踪、修改
    • State是只读的
      • 唯一修改State的方法一定是触发action,不要试图在其他地方通过任何的方式来修改State
      • 这样就确保了View或网络请求都不能直接修改state,它们只能通过action来描述自己想要如何修改stat;
      • 这样可以保证所有的修改都被集中化处理,并且按照严格的顺序来执行,所以不需要担心race condition(竟态)的问题;
    • 使用纯函数来执行修改
      • 通过reducer将 旧state和 action联系在一起,并且返回一个新的State:
      • 随着应用程序的复杂度增加,我们可以将reducer拆分成多个小的reducers,分别操作不同state tree的一部分
      • 但是所有的reducer都应该是纯函数,不能产生任何的副作用
  • 2.什么是纯函数
    • 返回结果只依赖于它的参数,并且在执行过程里面没有副作用
// 纯函数
function sum(num1, num2){return num1 + num2;
}// 非纯函数
let num1 = 10;
function sum(num2){return num1 + num2;
}// 纯函数
const num1 = 10;
function sum(num2){return num1 + num2;
}

3.基本使用

  • 准备工作

    • 创建 demo 目录
    • cd demo
    • npm init -y    #初始化一个node项目
    • npm install --save redux     #安装redux
  • redux的使用
    • store.subscribe()          #监听函数(一旦 state 发生变化,就自动执行这个函数)

    • store.getState()            #获取当前的 state

    • store.dispatch()            #派发 action(用于修改state)

// 导入redux
const redux = require('redux');// 1.定义一个状态(数据)
let initialState = {count: 0
}// 2.利用store保存状态
const store = redux.createStore(reducer);// 3.利用action修改状态
const addAction = {type:'ADD_COUNT', num: 1};
const subAction = { type: 'SUB_COUNT', num: -1};// 4.利用reduce关联store与action
function reducer(state = initialState, action){switch(action.type){case 'ADD_COUNT':return { count: state.count + action.num};case 'SUB_COUNT':return { count: state.count + action.num };default:return state;}
}// 在组件中如何使用?// 1.监听状态的改变
store.subscribe(()=>{console.log(store.getState());
}
)// 2.获取Store中存储的状态
console.log(store.getState());// 3.修改Store中存储的状态
store.dispatch(subAction);
// console.log(store.getState());
  • 当前代码存在的问题

    • 1.store、action、reducer代码都写在一个文件中,不利于维护
    • 2.action和reducer中都是使用字符串,来指定和判断操作类型, 写错不报错
    • 3.action中的操作写死了,不够灵活
  • 优化
const redux = require('redux');// 定义常量
const ADD_COUNT = 'ADD_COUNT';
const SUB_COUNT = 'SUB_COUNT';
// 定义一个状态
let initialState = {count: 0
};// 利用store来保存状态(state)
const store = redux.createStore(reducer);// 利用action来修改状态
// const addAction = {type:ADD_COUNT, num: 1};
// const subAction = {type:SUB_COUNT, num: -1};
const addAction = (num)=>{return {type:ADD_COUNT, num: num};
};
const subAction = (num)=>{return {type:SUB_COUNT, num: num};
};// 利用reducer将store和action串联起来
function reducer(state = initialState, action) {switch (action.type) {case ADD_COUNT:return {count: state.count + action.num};case SUB_COUNT:return {count: state.count - action.num};default:return state;}
}// 在组件中如何监听状态的改变?
store.subscribe((a)=>{console.log(store.getState());
});// 在组件中如何从Store中获取存储的状态?
console.log(store.getState());// 在组件中如何修改Store中存储的状态?
// store.dispatch(addAction(5));
store.dispatch(subAction(5));// console.log(store.getState());

4.结合 React

  • npm install --save redux
  • 在src目录下,新建store目录

store/constants.js

// 定义常量
export const ADD_COUNT = 'ADD_COUNT';
export const SUB_COUNT = 'SUB_COUNT';

store/store.js

import {createStore} from 'redux';
import reducer from './reducer';// 利用store来保存状态(state)
const store = createStore(reducer);export default store;

store/action.js

import {ADD_COUNT,SUB_COUNT
} from './constants';// 利用action来修改状态
// const addAction = {type:ADD_COUNT, num: 1};
// const subAction = {type:SUB_COUNT, num: -1};
export const addAction = (num)=>{return {type:ADD_COUNT, num: num};
};
export const subAction = (num)=>{return {type:SUB_COUNT, num: num};
};

store/reducer.js

import {ADD_COUNT,SUB_COUNT
} from './constants';// 定义一个状态
let initialState = {count: 666
};// 利用reducer将store和action串联起来
function reducer(state = initialState, action) {switch (action.type) {case ADD_COUNT:return {count: state.count + action.num};case SUB_COUNT:return {count: state.count - action.num};default:return state;}
}export default reducer;

App.js

import React from 'react';
import store from './store/store';
import {addAction, subAction} from './store/action';class App extends React.PureComponent{constructor(props){super(props);this.state = {// 1.getState():获取存储的状态(数据)count: store.getState().count}}// componentDidMount:当组件被挂载时(已经完成渲染),react会自动调用该方法componentDidMount() {// 3.subscribe():监听状态的改变store.subscribe(()=>{// 将修改后的数据重新存储到state中this.setState({count: store.getState().count})})}// componentWillUnmount:当组件被卸载时,react会自动调用该方法componentWillUnmount() {// 4.unsubscribe():移除监听状态的改变事件store.unsubscribe();}render(){return(<div><p>{this.state.count}</p><button onClick={()=>{this.btnClick()}}>增加</button></div>)}btnClick(){// 2.dispatch():修改Store中存储的状态store.dispatch(addAction(5));}
}export default App;
  • 存在问题:

    • 1.冗余代码太多, 每次使用都需要在构造函数中获取
    • 2.每次使用都需要监听和取消监听
    • 3.操作store的代码过于分散
  • 如何优化:
    • 如何解决冗余代码太多问题

      • 使用 React-Redux
    • 什么是 React-Redux
      • React-Redux是Redux官方的绑定库,能够让我们在组件中更好的读取和操作Redux 保存的状态
      • 安装react-reduct: npm install react-reduct

index.js

import ReactDOM from 'react-dom';
import React from 'react';
import App from './App';
import { Provider } from 'react-redux'
import store from './store/store';ReactDOM.render(// 只要利用Provider将祖先组件包裹起来// 并且通过Provider的store属性将Redux的store传递给Provider// 那么就可以在所有后代中直接使用Redux了<Provider store={store}><React.StrictMode><App/></React.StrictMode></Provider>, document.getElementById('root'));

components/Home.js

import React from 'react';
import { connect } from 'react-redux';
import {addAction, subAction} from '../store/action';class Home extends React.PureComponent{render(){return (<div>{/* 3.通过props来使用redux中保存的数据 */}<p>{this.props.count}</p><button onClick={()=>{this.props.increment()}}>递增</button></div>)}
}
// 1.mapStateToProps方法:告诉React-Redux, 需要将store中保存的哪些数据映射到当前组件的props上
const mapStateToProps = (state)=>{return{count: state.count}
}
// 2.mapDispatchToProps方法:告诉React-Redux, 需要将哪些派发的任务映射到当前组件的props上
const mapDispatchToProps = (dispatch)=>{return{increment(){dispatch(addAction(1));}}
}
// 4.connect:关联Home组件与mapStateToProps和mapDispatchToProps方法
export default connect(mapStateToProps, mapDispatchToProps)(Home);

5.Redux 处理网络请求

  • 前提

    • 1.搭建一个Egg项目
    • 2.快速启动Egg项目( npm run dev )
    • 3.输入:localhost:7001/info  即可访问页面

store/constants.js

// 定义常量
export const ADD_COUNT = 'ADD_COUNT';
export const SUB_COUNT = 'SUB_COUNT';
export const CHANGE_INFO = 'CHANGE_INFO';

store/store.js

import {createStore} from 'redux';
import reducer from './reducer';// 利用store来保存状态(state)
const store = createStore(reducer);export default store;

store/action.js

import {ADD_COUNT,SUB_COUNT,CHANGE_INFO
} from './constants';// 利用action来修改状态
// const addAction = {type:ADD_COUNT, num: 1};
// const subAction = {type:SUB_COUNT, num: -1};
export const addAction = (num)=>{return {type:ADD_COUNT, num: num};
};
export const subAction = (num)=>{return {type:SUB_COUNT, num: num};
};
export const changeAction = (info)=>{return {type:CHANGE_INFO, info: info};
};

store/reducer.js

import {ADD_COUNT,SUB_COUNT,CHANGE_INFO
} from './constants';// 定义一个状态
let initialState = {count: 666,info: {}
};// 利用reducer将store和action串联起来
function reducer(state = initialState, action) {switch (action.type) {case ADD_COUNT:return {...state, count: state.count + action.num};case SUB_COUNT:return {...state, count: state.count - action.num};case CHANGE_INFO:return {...state, info: action.info};default:return state;}
}export default reducer;

components/About.js

import React from 'react';
import { connect } from 'react-redux';
import { addAction, changeAction } from '../store/action';class About extends React.PureComponent {// componentDidMount:已经挂载(渲染完成)时,react会自动调用该方法componentDidMount() {// 发送GET请求fetch('http://localhost:7001/info').then((response) => {// 转换为json格式return response.json();}).then((data) => {// console.log(data);this.props.changeInfo(data);}).catch((error) => {console.log(error);})}render() {return (<div>{/* 3.通过props来使用redux中保存的数据 */}<p>{this.props.count}</p><button onClick={() => { this.props.increment() }}>递增</button><p>{this.props.info.name}</p><p>{this.props.info.age}</p></div>)}
}
// 1.mapStateToProps方法:告诉React-Redux, 需要将store中保存的哪些数据映射到当前组件的props上
const mapStateToProps = (state) => {return {count: state.count,info: state.info}
}
// 2.mapDispatchToProps方法:告诉React-Redux, 需要将哪些派发的任务映射到当前组件的props上
const mapDispatchToProps = (dispatch) => {return {increment() {dispatch(addAction(1));},changeInfo(info) {dispatch(changeAction(info));}}
}
// 4.connect:关联Home组件与mapStateToProps和mapDispatchToProps方法
export default connect(mapStateToProps, mapDispatchToProps)(About);

6.Redux-thunk 中间件

  • 优化:将 异步请求 封装到 Redux 中

  • 1.当前保存异步数据存在的问题
    • 异步数据既然要保存到Redux中, 所以获取异步数据也应该是Redux的一部分
    • 所以获取异步数据的代码应该放到Redux中, 而不是放到组件生命周期方法中
  • 2.如何在Redux中 获取网络数据
    • 使用 redux-thunk 中间件
  • 3.redux-thunk 作用
    • 默认情况下 dispatch  只能接收一个对象
    • 使用 redux-thunk 可以让 dispatch 除了可以接收一个对象以外, 还可以接收一个函数
    • 通过 dispatch 派发一个函数的时候能够去执行这个函数, 而不是执行 reducer 函数
  • 4.redux-thunk 如何使用
    • 安装 redux-thunk

      • npm install redux-thunk
    • 在创建 store 时应用 redux-thunk 中间件
    • 在 action 中获取网络数据
    • 在组件中派发 action

store/store.js

import { createStore, applyMiddleware } from 'redux';
import reducer from './reducer';
// 1.导入thunkMiddleware中间件
import thunkMiddleware from 'redux-thunk';// 2.应用thunkMiddleware中间件
// 在创建store之前, 通过applyMiddleware方法, 告诉Redux需要应用哪些中间件
const storeEnhancer = applyMiddleware(thunkMiddleware);
// 利用store来保存状态(state)
const store = createStore(reducer, storeEnhancer);export default store;

store/action.js

import {ADD_COUNT,SUB_COUNT,CHANGE_INFO
} from './constants';// 利用action来修改状态
// const addAction = {type:ADD_COUNT, num: 1};
// const subAction = {type:SUB_COUNT, num: -1};
export const addAction = (num) => {return { type: ADD_COUNT, num: num };
};
export const subAction = (num) => {return { type: SUB_COUNT, num: num };
};
export const changeAction = (info) => {return { type: CHANGE_INFO, info: info };
};// 定义getUserInfo方法,在这个方法中发送网络请求并派发任务
export const getUserInfo = (dispatch, getState)=>{// 发送GET请求fetch('http://localhost:7001/info').then((response) => {// 转换为json格式return response.json();}).then((data) => {// console.log(data);// dispatch:派发任务dispatch(changeAction(data));}).catch((error) => {console.log(error);})
}

components/About.js

import React from 'react';
import { connect } from 'react-redux';
import { addAction, getUserInfo } from '../store/action';class About extends React.PureComponent {// componentDidMount:已经挂载(渲染完成)时,react会自动调用该方法componentDidMount() {// 调用changeInfo方法this.props.changeInfo();}render() {return (<div>{/* 3.通过props来使用redux中保存的数据 */}<p>{this.props.count}</p><button onClick={() => { this.props.increment() }}>递增</button><p>{this.props.info.name}</p><p>{this.props.info.age}</p></div>)}
}
// 1.mapStateToProps方法:告诉React-Redux, 需要将store中保存的哪些数据映射到当前组件的props上
const mapStateToProps = (state) => {return {count: state.count,info: state.info}
}
// 2.mapDispatchToProps方法:告诉React-Redux, 需要将哪些派发的任务映射到当前组件的props上
const mapDispatchToProps = (dispatch) => {return {increment() {dispatch(addAction(1));},changeInfo() {// dispatch(changeAction(info));// 注意点: 默认情况下dispatch方法只能接收一个对象//        如果想让dispatch方法除了可以接收一个对象以外, 还可以接收一个方法//        那么我们可以使用 redux-thunk 中间件// redux-thunk中间件作用:// 让dispatch方法可以接收一个函数, 让我们在通过dispatch派发任务的时候去执行我们传入的方法// 在dispatch派发任务时,直接执行getUserInfo方法dispatch(getUserInfo);}}
}
// 4.connect:关联Home组件与mapStateToProps和mapDispatchToProps方法
export default connect(mapStateToProps, mapDispatchToProps)(About);

7.Redux-saga 中间件

  • 1.什么是 Redux-saga

    • redux-saga 和 redux-thunk 一样,是一个 Redux 中获取存储异步数据的中间件
    • redux-saga 可以直接拦截 dispatch 派发的 action, 从而实现在执行 reducer 之前执行     一些其它操作
  • 2.如何使用 Redux-saga
    • 1.安装 Redux-saga

      • npm install redux-saga
    • 2.在创建 store 时,应用 redux-thunk 中间件
    • 3.在生成器函数中获取网络数据
    • 4.在组件中派发 action

store/store.js

import { createStore, applyMiddleware } from 'redux';
import reducer from './reducer';
import mySaga from './saga';
/*
注意点: 如果导入的是redux-thunk, 那么返回给我们的是一个中间件对象如果导入的是redux-saga, 那么返回给我们的是一个用于创建中间件对象的方法
* */
// import thunkMiddleware from 'redux-thunk';// 1.导入中间件方法
import createSagaMiddleware from 'redux-saga';// 2.通过createSagaMiddleware方法,创建saga中间件对象
const sagaMiddleware = createSagaMiddleware();// 3.应用sagaMiddleware中间件
// 在创建store之前, 通过applyMiddleware方法, 告诉Redux需要应用哪些中间件
const storeEnhancer = applyMiddleware(sagaMiddleware);// 利用store来保存状态(state)
const store = createStore(reducer, storeEnhancer);/*
注意点: 如果是redux-thunk, 那么在创建store的时候指定完中间件即可如果是redux-saga, 那么除了需要在创建store的时候指定中间件以外, 还需要手动的调用中间件的run方法才行
* */
// 4.拦截 action
// 利用传入的生成器告诉redux-saga, 需要拦截哪些dispatch派发的action
sagaMiddleware.run(mySaga);export default store;

store/constants.js

// 定义常量
export const ADD_COUNT = 'ADD_COUNT';
export const SUB_COUNT = 'SUB_COUNT';
export const CHANGE_INFO = 'CHANGE_INFO';
export const GET_USER_INFO = 'GET_USER_INFO';

store/soga.js

import { takeEvery, put } from 'redux-saga/effects'
import { GET_USER_INFO } from './constants';
import { changeAction } from './action';function *myHandler() {// 获取网络数据const data = yield fetch('http://127.0.0.1:7001/info').then((response) => {return response.json();}).catch((error) => {console.log(error);});// console.log(data);// 保存获取到的数据,相当于 store.dispatch(changeAction());yield put(changeAction(data));
}
function *mySaga() {// 第一个参数:指定需要拦截的action类型// 第二个参数:指定拦截到这个类型的action之后交给谁来处理yield takeEvery(GET_USER_INFO, myHandler)
}export default mySaga;

store/action.js

import {ADD_COUNT,SUB_COUNT,CHANGE_INFO,GET_USER_INFO
} from './constants';// 利用action来修改状态
export const addAction = (num) => {return { type: ADD_COUNT, num: num };
};
export const subAction = (num) => {return { type: SUB_COUNT, num: num };
};
export const changeAction = (info) => {return { type: CHANGE_INFO, info: info };
};export const getUserInfo = () => {return { type: GET_USER_INFO }
}

store/reducer.js

import {ADD_COUNT,SUB_COUNT,CHANGE_INFO
} from './constants';// 定义一个状态
let initialState = {count: 666,info: {}
};// 利用reducer将store和action串联起来
function reducer(state = initialState, action) {switch (action.type) {case ADD_COUNT:return { ...state, count: state.count + action.num };case SUB_COUNT:return { ...state, count: state.count - action.num };case CHANGE_INFO:return { ...state, info: action.info };default:return state;}
}export default reducer;

components/About.js

import React from 'react';
import { connect } from 'react-redux';
import { addAction, getUserInfo } from '../store/action';class About extends React.PureComponent {// componentDidMount:已经挂载(渲染完成)时,react会自动调用该方法componentDidMount() {// 调用changeInfo方法this.props.changeInfo();}render() {return (<div>{/* 3.通过props来使用redux中保存的数据 */}<p>{this.props.count}</p><button onClick={() => { this.props.increment() }}>递增</button><p>{this.props.info.name}</p><p>{this.props.info.age}</p></div>)}
}
// 1.mapStateToProps方法:告诉React-Redux, 需要将store中保存的哪些数据映射到当前组件的props上
const mapStateToProps = (state) => {return {count: state.count,info: state.info}
}
// 2.mapDispatchToProps方法:告诉React-Redux, 需要将哪些派发的任务映射到当前组件的props上
const mapDispatchToProps = (dispatch) => {return {increment() {dispatch(addAction(1));},changeInfo() {// 在dispatch派发任务时,直接执行getUserInfo方法// dispatch(getUserInfo);// dispatch 接收一个对象dispatch(getUserInfo());}}
}
// 4.connect:关联Home组件与mapStateToProps和mapDispatchToProps方法
export default connect(mapStateToProps, mapDispatchToProps)(About);

Redux-saga 补充:

  • takeEvery和takeLatest区别在于:是否能够完整的执行监听方法

    • 对于takeEvery而言, 每次拦截到对应类型的action, 都会完整的执行监听方法
    • 对于takeLatest而言, 每次拦截到对应类型的action, 都不能保证一定能够完整的              执行监听方法

store/saga.js

import {takeEvery, takeLatest, put, all} from 'redux-saga/effects'
import {GET_USER_INFO, ADD_COUNT, SUB_COUNT} from './constants';
import {changeAction} from './action';function *myHandler() {// 获取网络数据const data1 = yield fetch('http://127.0.0.1:7001/info').then((response)=>{return response.json();}).catch((error)=>{console.log(error);});const data2 = yield fetch('http://127.0.0.1:7001/info').then((response)=>{return response.json();}).catch((error)=>{console.log(error);});/*如果我们只需要保存一个数据, 那么直接通过 yield put 即可但是如果我们想同时保存多个数据, 那么我们就必须借助另外一个函数:all()* */// yield put(changeAction(data));yield all([yield put(changeUserAction(data1)),yield put(changeInfoAction(data2)),yield put({type:'CHANGE_USER_NAME', name: data1.name}),yield put({type:'CHANGE_USER_Age', name: data1.age}),])console.log('执行到了监听方法的最后', data);
}
function *mySaga() {/*takeEvery和takeLatest区别: 是否能够完整的执行监听方法对于takeEvery而言, 每次拦截到对应类型的action, 都会完整的执行监听方法对于takeLatest而言, 每次拦截到对应类型的action, 都不能保证一定能够完整的执行监听方法例如: 连续派发了3次GET_USER_INFO的action那么对于takeEvery而言, myHandler就会被完整的执行3次那么对于takeLatest而言, 如果派发下一次同类型action的时候上一次派发的action还没有处理完, 也就是上一次的监听方法还没有处理完那么takeLatest会放弃还没有处理完的代码, 直接开始处理下一次的action* */// yield takeEvery(GET_USER_INFO, myHandler)// yield takeLatest(GET_USER_INFO, myHandler)/*如果我们只需要拦截一个类型的action, 那么直接通过 yield takeEvery / yield takeLatest即可但是如果我们想同时拦截多个类型的action, 那么我们就必须借助另外一个函数: all()* */yield all([yield takeEvery(GET_USER_INFO, myHandler),yield takeEvery(ADD_COUNT, myHandler),yield takeEvery(SUB_COUNT, myHandler),]);
}
export default mySaga;

Redux 的基本使用相关推荐

  1. operate函数_跟着 redux 学 compose组合函数

    ▲ 点击上方蓝字关注我 ▲ 把你的心 我的心串一串 串一株幸运草 串一个同心圆 文 / 景朝霞 来源公号 / 朝霞的光影笔记 ID / zhaoxiajingjing 目录0 / 热热身1 / red ...

  2. Redux 入门教程(三):React-Redux 的用法

    前两篇教程介绍了 Redux 的基本用法和异步操作,今天是最后一部分,介绍如何在 React 项目中使用 Redux. 为了方便使用,Redux 的作者封装了一个 React 专用的库 React-R ...

  3. Redux 入门教程(二):中间件与异步操作

    上一篇文章,我介绍了 Redux 的基本做法:用户发出 Action,Reducer 函数算出新的 State,View 重新渲染. 但是,一个关键问题没有解决:异步操作怎么办?Action 发出以后 ...

  4. Redux 入门教程(一):基本用法

    一年半前,我写了<React 入门实例教程>,介绍了 React 的基本用法. React 只是 DOM 的一个抽象层,并不是 Web 应用的完整解决方案.有两个方面,它没涉及. 代码结构 ...

  5. Koa2和Redux中间件源码研究

    一.Koa2中间件源码分析 在Koa2中,中间件被存放在一个数组中. 使用koa中,最常见的就是app.use(fn),use函数部分源码如下所示.首先中间件必须是个函数.若是generator函数, ...

  6. React+Redux+中间件

    MVVM是Model-View-ViewModel的缩写.mvvm是一种设计思想.Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑:View 代表UI 组件,它负责将数据模 ...

  7. redux rxjs_可观察的RxJS和Redux入门指南

    redux rxjs Redux-Observable is an RxJS-based middleware for Redux that allows developers to work wit ...

  8. redux logic_Redux-Logic简介

    redux logic by Sam Ollason 通过萨姆·奥拉森(Sam Ollason) Redux-Logic简介 (An Introduction to Redux-Logic) This ...

  9. 使用Typescript的巧妙React上下文技巧-不是Redux

    by Bill Girten 比尔·吉尔滕(Bill Girten) 使用Typescript的巧妙React上下文技巧- 不是 Redux (Clever React context tricks ...

  10. redux 局部刷新_如何使用Redux Observables和刷新令牌API获取新的访问令牌

    redux 局部刷新 by Sachin Kumar 由Sachin Kumar 如何使用Redux Observables和刷新令牌API获取新的访问令牌 (How to get a new acc ...

最新文章

  1. 深入理解ElasticSearch(八):索引管理
  2. 安卓app与阿里云服务器的无线通信(非局域网)
  3. (需求实战_终章) SpringBoot2.x 整合RabbitMQ
  4. 拼图登陆拼图二维码验证_如何使用拼图快速轻松地构建静态网站
  5. 玩转 SpringBoot 2 之整合 JWT 上篇
  6. 开源视频监控系统:iSpy
  7. cad画流程图的插件_如何用cad画交互流程图
  8. 硬盘数据恢复软件免费版有免费使用的吗
  9. Android推送服务——百度云推送
  10. Word提示:“向程序发送命令时出现问题”解决方法
  11. 安卓实训项目源码_实训2019 | 联想云实训心得
  12. mac下生成.icns图标
  13. 【绝对干货】kafka偏移量设置
  14. 解决nasm/yasm not found or too old. Use --disable-x86asm for a crippled build报错
  15. 《大话设计模式》精髓理解——Chapter 01 - 05 开放封闭与依赖倒转
  16. Hollo world
  17. 卓训教育:打败挫败感,让孩子对学习更自信
  18. 【2020.10.31 洛谷团队赛 普及组】T2 U138180 神仙数论题
  19. 促销活动 (优先队列的应用)
  20. word转pdf后书签目录失效解决方法

热门文章

  1. Win10家庭版 傻瓜安装datahub的备忘一则
  2. CTFHub笔记之WEB文件上传:无验证、前端验证、文件头检查
  3. 干货满满的 GopherChina2021 北京大会 PPT is coming
  4. MathJax:微积分常用符号
  5. 批量添加用户脚本--Linux bash
  6. 输入一个8bit数,输出其中1的个数。如果只能使用1bit全加器,最少需要几个,请使用verilog进行描述?(附verilog代码)
  7. [ext4]空间管理 - 分配机制
  8. LeetCode 2248、多个数组求交集
  9. 个人博客标签和文章的表结构设计
  10. 开源开放 | 多模态地球科学知识图谱GAKG