Context
创建 Context 对象
// context.ts
const MyContext = React.createContext(defaultValue);
提供 Context 对象
import MyContext from './context';
class APP extends React.Component {
construct(props) {
super(props);
// value 值为对象时,状态提升至 state,防止父组件刷新引起子组件不必要的渲染
this.state = {
theme: themes.light,
toggleTheme: this.toggleTheme,
};
this.toggleTheme = this.toggleTheme.bind(this);
}
// 改变主题色方法
toggleTheme () {
this.setState(state => ({
theme: state.theme === themes.dark
? themes.light
: themes.dark,
}));
}
render() {
return (
<MyContext.Provider value={this.state}>
{this.props.children}
</MyContext.Provider>
)
}
}
订阅 Context 对象
// 方法1:
class MyClass extends React.Component {
componentDidMount() {
let value = this.context;
/* 在组件挂载完成后,使用 MyContext 组件的值来执行一些有副作用的操作 */
}
render() {
let value = this.context;
/* 基于 MyContext 组件的值进行渲染 */
}
}
MyClass.contextType = MyContext;
// 方法2: public class fields 语法【实验性语法】
class MyClass extends React.Component {
static contextType = MyContext;
render() {
let value = this.context;
/* 基于这个值进行渲染工作 */
}
}
消费 Context 对象
import { MyContext } from './context';
function ThemeTogglerButton() {
// Theme Toggler 按钮不仅仅只获取 theme 值,它也从 context 中获取到一个 toggleTheme 函数
return (
<MyContext.Consumer>
{(context) => {
const {theme, toggleTheme} = context;
return (
<button onClick={toggleTheme}
style={{backgroundColor: theme.background}}
>
Toggle Theme
</button>
)
}}
</MyContext.Consumer>
);
}
export default ThemeTogglerButton;
更多详细使用:
Mobx
创建 observable 对象
说明:
@observable
表示数据可监控, 是全局数据@action
表示修改全局共享数据的方法
RootStore
// mobx/index.ts
import { observable, action } from "mobx";
class RootStore {
// 手机号码
@observable mobile = '';
// token
@observable token = '';
// 设置数据信息
@action setUserInfo(mobile, token) {
this.mobile = mobile;
this.token = token;
}
// 清除数据信息
@action clearUserInfo() {
this.mobile = '';
this.token = '';
}
}
export default new RootStore();
UserStore
// mobx/userStore.ts
import { observable, action } from "mobx";
class UserStore {
// 用户信息对象
@observable user = {};
// 设置用户信息
@action setUser(user) {
this.user = user;
};
// 清除用户信息
@action clearUser() {
this.user = {};
}
}
export default new UserStore();
提供 observable 对象
import React from 'react';
import { Provider} from 'mobx-react';
import RootStore from './mobx';
import UserStore from './mobx/userStore'
const APP = (props) => {
return (
<Provider RootStore={RootStore} UserStore={UserStore}>
{props.children}
</Provider>
)
}
注入、订阅 observable 对象
-
@inject("RootStore") 注入
observable
对象,获取全局数据RootStore
-
@observer 监听
observable
对象数据变更,重新渲染更新组件的全局数据
类组件
import React from 'react';
import { inject, observer } from 'mobx-react';
@inject('RootStore') // 注入 RootStore
@inject('UserStore') // 注入 UserStore
@observer
class Demo extends React.Component {
componentDidMount() {
// 获取 mobx 内的 RootStore 对象
console.log(this.props.RootStore);
}
render() {
return null
}
}
函数组件
import React from 'react';
import { inject, observer } from 'mobx-react';
const Demo = (props) => {
React.useEffect(() => {
// 获取 mobx 内的 RootStore 对象
console.log(props.RootStore);
}, []);
return null
}
// 注入 RootStore
export default inject('RootStore')(observer(Demo));
// 注入 RootStore、 UserStore
export default inject('RootStore')(inject('UserStore')(observer(Demo)));
Redux
Redux
是一个使用叫做action
的事件来管理和更新应用状态的模式和工具库
创建 reducer 纯函数
返回值: 最新状态值 state
// 初始 state 值
const initialState = [];
// reducer 纯函数
const reducer = (state = initialState, action) => {
switch(action.type) {
// 重置 state
case 'reset':
return { ...action.state };
// 更新 state
case 'update':
return Object.assign({}, state, action.payload);
default:
return state;
}
}
export default reducer;
说明: 通过分发的
action
的type
类型执行相应的数据更新操作
整合多个 reducer
将多个
reducer
纯函数进行整合并可以进行重新命名
import { combineReducers } from 'redux';
import test1Reducer from './test1Reducer';
import test2Reducer from './test2Reducer';
const reducer = combineReducers({
test1: test1Reducer,
test2: test2Reducer
});
创建数据源 store
// store.ts
import reducer from './reducer';
const store = createStore(reducer);
提供 Store
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import App from './App'
import store from './store'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
connect
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
mapStateToProps
mapStateToProps
是一个函数,映射 store
中的数据到组件的 props
中
mapStateToProps(state, ownProps):stateProps
参数:
- state
Redux
中的store
- ownProps 组件自身的
props
属性
返回值: 返回一个 object
对象, 会将该返回值对象与 props
合并
说明:
mapStateToProps
会依据参数来订阅store
或ownProps
的状态改变(写了该参数就会订阅,没写就不会订阅)
示例
class Demo extends Component {
static PropTypes = {
userId: PropTypes.string.isRequired,
user: PropTypes.object
};
render(){
return <div>用户名:{this.props.user.name}</div>
}
}
const mapStateToProps = (state, ownProps) => {
// state 是 { userList: [{id: 0, name: '王二'}] }
return {
// 查找 store 中 userList 数据源中 id 为 userId 的用户数据传递给 props
user: _.find(state.userList, {id: ownProps.userId})
}
}
const MyComp = connect(mapStateToProps)(Demo);
mapDispatchToProps
mapDispatchToProps
用于建立组件跟 store.dispatch
的映射关系, 可以是一个 object
,也可以传入函数
mapDispatchToProps(dispatch, ownProps): dispatchProps
参数:
- dispatch 分发
action
函数 - ownProps 组件自身的
props
属性
mapDispatchToProps 的三种方式
- 当
connect(mapState, null)
不传递第二个参数(或为null
) 时
this.props.dispatch({
type: ChangeColor,
payload: {
color: e.target.value
}
})
- 当
connect(mapState, mapDispatch)
的第二个参数为函数时
// mapDispatch 为一个函数
const mapDispatchToProps = (dispatch) => ({
changeColor : (value) => (dispatch({
type:ChangeColor,
payload:{
color: value
}
})),
})
- 当
connect(mapState,mapDispatch)
的第二个参数为对象时
// mapDispatch 为一个对象
const changeColor = (v) => ({
type: ChangeColor,
payload:{
color:v
}
})
const mapDispatchToProps = {
changeColor ,
}
Redux
本身也提供了 bindActionCreators
函数,来将 action
包装成直接可被调用的函数。
import { bindActionCreators } from 'redux';
const changeColor = {
type: ChangeColor,
payload:{
color: value
}
}
const mapDispatchToProps = (dispatch, ownProps) => {
return bindActionCreators({
changeColor,
});
}
react-thunk
在创建 store
文件中创建 thunk
中间件
安装
npm install react-thunk
创建 Store 文件
import { createStore, applyMiddleware ,compose } from 'redux’;
import thunk from 'redux-thunk’;
import reducer from './reducers’;
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const enhancer = composeEnhancers(applyMiddleware(thunk))
let store = createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());
let store = createStore(reducer, enhancer);
export default store;
创建 Action Type 文件
export const UPDATE_List = 'update_list';
创建 Action 文件
// actions.ts
// 更新数据信息
const changeArticles = (data) => {
return {
type: UPDATE_List,
data,
}
}
// redux-thunk actionCreator【创建的 action 函数可以返回一个函数(即可以调用 axios 执行异步请求数据操作)】
export const getDataAxAction = (params) => {
return (dispatch, getState) => {
axios.get(url, { params })
.then((res)=>{
// res.data.data.list【获取到查询结果后再次分发action,创建action并将异步请求结果赋值给action.value上】
dispatch(changeArticles(res.data.data.list));
}).catch((error)=>{
console.log(error);
})
};
}
组件内使用
import React from 'react';
import { getDataAxAction } from './actions';
class Demo extends React.Component {
// 改变 params 来获取最新的 list 数据信息
updateList() {
const params = { page: 0, pageSize: 10 };
this.props.updateList(params);
}
render(){
const { list } = this.props;
return (
<div onClick={updateList}>更新 list 数据</div>
)
}
}
// 映射 state to props
const mapStateToProps = (state, ownProps) => {
return {
list: state.data
}
}
// 映射 dispatch to props
const mapDispatchToProps = (dispatch) => ({
updateList : (params) =>(
dispatch(getDataAxAction(params))
),
})
const MyComp = connect(mapStateToProps, mapDispatchToProps)(Demo);
react-saga
在创建 store
文件中创建 saga
中间件
安装
npm install react-saga
创建 store 文件
import { createStore, applyMiddleware, compose } from 'redux’;
import reducer from './reducers’;
import createSagaMiddleware from 'redux-saga’;
import mySagas from './mySagas’;
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const sagaMiddleware = createSagaMiddleware();
const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware))
let store = createStore(reducer, enhancer);
//在这里使用 mySagas【在store创建好后,中间件挂好后在使用mySagas】
sagaMiddleware.run(mySagas);
export default store;
创建 Action Type 文件
export const UPDATE_PARAMS = 'update_params';
export const UPDATE_List = 'update_list';
创建 Action 文件
// actions.ts
// 更新 params 数据信息
const updateParams = (params) => {
return {
type: UPDATE_PARAMS,
params,
}
}
// 更新数据信息
const changeArticles = (data) => {
return {
type: UPDATE_List,
data,
}
}
创建 mySagas 文件
import { takeEvery, put } from ‘redux-saga/effects’;
//创建 mySagas【generator函数】函数后,在创建 store 仓库中使用 mySagas【saga 中间插件调用 run 方法使用】
function* mySagas(){
//监听某个 action, 然后执行第二个参数 gengerator 函数
yield takeEvery(UPDATE_PARAMS, getList);
}
//参数 action 就是对应的 action 对象
function* getList(action){
//发送异步,异步成功后分发 action
let res = yield axios.get(url, { params: action.params });
//put 就是转发 action,类似于 dispatch,然后执行同步请求执行相应的业务逻辑处理
yield put(changeArticles(res.data.list));
}
组件内使用
import React from 'react';
import { updateParams } from './actions';
class Demo extends React.Component {
// 改变 params 来获取最新的 list 数据信息
changeParams() {
const params = { page: 0, pageSize: 10 };
this.props.changeParams(params);
}
render(){
const { list } = this.props;
return (
<div onClick={changeParams}>更新 list 数据</div>
)
}
}
// 映射 state to props
const mapStateToProps = (state, ownProps) => {
return {
list: state.data
}
}
// 映射 dispatch to props
const mapDispatchToProps = (dispatch) => ({
changeParams : (params) =>(
dispatch(updateParams(params))
),
})
const MyComp = connect(mapStateToProps, mapDispatchToProps)(Demo);
react-thunk 与 react-saga 之间的区别
react-thunk
// redux-thunk actionCreator【创建的 action 函数可以返回一个函数(即可以调用 axios 执行异步请求数据操作)】
export const getDataAxAction = (params) => {
return (dispatch, getState) => {
axios.get(url, { params })
.then((res) => {
// res.data.data.list【获取到查询结果后再次分发action,创建action并将异步请求结果赋值给action.value上】
dispatch(changeArticles(res.data.data.list));
}).catch((error) => {
console.log(error);
})
};
}
说明:
当我们返回的是函数时,store
会帮我们调用这个返回的函数,并且把 dispatch
暴露出来供我们使用。对于 redux-thunk
的整个流程来说,它是等异步任务执行完成之后,我们再去调用 dispatch
,然后去 store
去调用 reducer
。
react-saga
import { takeEvery,put } from ‘redux-saga/effects’;
//创建 mySagas【generator函数】函数后,在创建 store 仓库中使用 mySagas【saga 中间插件调用 run 方法使用】
function* mySagas(){
//监听某个 action, 然后执行第二个参数 gengerator 函数
yield takeEvery(UPDATE_PARAMS, getList);
}
//参数 action 就是对应的 action 对象
function* getList(action){
//发送异步,异步成功后分发 action
let res = yield axios.get(url, { params: action.params });
//put 就是转发 action,类似于 dispatch,然后执行同步请求执行相应的业务逻辑处理
yield put(changeArticles(res.data.list));
}
说明:
当我们 dispatch
的 action
类型不在 reducer
中时,redux-saga
的监听函数 takeEvery
就会监听到,等异步任务有结果就执行 put
方法,相当于 dispatch
,再一次触发 dispatch
。对于 redux-saga
的整个流程来说,它是等执行完 action
和 reducer
之后,判断 reducer
中有没有这个 action
。