创建store
添加依赖
npm install react-redux redux redux-thunk
创建reducer
redux/reducer/fetchState.ts
const initialState = false;//初始状态
const fetchState = (state = initialState, action:any) => {
switch (action.type) {
case 'set_fetch_state': //操作类型
return action.payload; //返回状态
default:
return state;
}
};
export default fetchState; //导出reducer
redux/reducer/map.ts
const initialState = {
name: null,
info: {
age: null,
address: null
}
}; //初始状态
const map = (state = initialState, action:any) => {
switch (action.type) { //操作类型
case 'update_name':
return { ...state, name: action.payload };//payload是操作参数,返回新的状态
case 'update_age':
return { ...state, info: { ...state.info, age: action.payload } };
case 'update_address':
return { ...state, info: { ...state.info, address: action.payload } };
case 'init_state':
return action.payload;
default:
return state;
}
};
export default map;//导出reducer
redux/reducer/index.ts
import { combineReducers } from 'redux';
import map from './map';
import fetchState from './fetchState';
const reducers = combineReducers( //合并两个reducer为一个reducer
{
map,
fetchState
});
export default reducers; //导出合并后的reducer
创建action
redux/stateAction.ts
//store.dispatch(stateAction.xxx)来修改状态
export const update_name = (name: string) => {
return {
type: 'update_name', //操作类型
payload: name //操作参数
}
}
export const update_age = (age: string) => {
return {
type: 'update_age',
payload: age
}
}
export const update_address = (address: string) => {
return {
type: 'update_address',
payload: address
}
}
export const init_state = (state: any) => {
return {
type: 'init_state',
payload: state
}
}
export const set_fetch_state = (state: boolean) => {
return {
type: 'set_fetch_state',
payload: state
}
}
创建store
App.tsx
import {
applyMiddleware as applyReduxMiddleware,
createStore as createReduxStore
} from 'redux';
import thunk from 'redux-thunk';//异步dispatch使用,之后会介绍
import reducers from './redux/reducer';//导入reducer
const reduxMiddlewares = [thunk];
//创建store
const store = createReduxStore(
reducers,//reducer
undefined, //初始值
applyReduxMiddleware(...reduxMiddlewares)//store中间处理
);
创建组件
创建组件
component/MapComponent.jsx
import React, { Component } from 'react';
import {
Text,
View,
Button
} from 'react-native'; //组件库中导入组件
export default class MapComponent extends React.Component {//继承自React.Component
render() { //render方法渲染组件
const {
client,
map,
fetchState,
update_name,
update_age,
update_address
} = this.props;//获取所有组件属性
if (!fetchState) {
return <Text>Loading...</Text>;//正在获取数据,显示加载中
}else{
return (//获取数据完成,展示数据
<View>
<Text>Map Component</Text>
<Text>Name: {map.name}</Text>
<Text>Age: {map.info.age}</Text>
<Text>Address: {map.info.address}</Text>
<Button onPress={() => update_name('Jane')} title='Update Name'/>
<Button onPress={() => update_age('200')} title='Update Age'/>
<Button onPress={() => update_address('sx')} title='Update Address'/>
</View>
);
}
}
}
store添加到上下文
App.tsx
//Provider放在最外面,所有在Provider中的组件都可以获得store
import { Provider } from 'react-redux';
return (
<Provider store={store}>
</Provider>);
store状态以及dispatch方法映射到组件属性
Context.js
export function withContext(Component)
{
return (props) => ( //prop传递给组件
<Component {...props} />
);
}
修改component/MapComponent.jsx
import { withContext } from '../Context'; //导入Context
import { connect } from 'react-redux';//connect用于将上下文中的store根据map方法映射为组件的props
import * as stateAction from '../redux/stateAction';//导入action
const mapStateToProps = (state) => {//store.state映射到字段类型属性
return {
map: state.map,//字段属性map
fetchState: state.fetchState,
};
};
const mapDispatchToProps = (dispatch) => {//store.dispatch映射到方法类型属性
return {
update_name: (name) => {//方法属性update_name
dispatch(stateAction.update_name(name));
},
update_age: (age) => {
dispatch(stateAction.update_age(age));
},
update_address: (address) => {
dispatch(stateAction.update_address(address));
},
};
};
const Container = withContext(connect(
mapStateToProps,
mapDispatchToProps
)(MapComponent));//映射属性到组件
export default Container;//导出映射后的组件
组件中使用dispatch方法
修改component/MapComponent.jsx
export default class MapComponent extends React.Component {
render() {
const {
client,
map,
fetchState,
update_name,
update_age,
update_address
} = this.props;
if (!fetchState) {
return <Text>Loading...</Text>;
}else{
return (
<View>
<Text>Map Component</Text>
<Text>Name: {map.name}</Text>
<Text>Age: {map.info.age}</Text>
<Text>Address: {map.info.address}</Text>
<Button onPress={() => update_name('Jane')} title='Update Name'/>//使用dispatch方法update_name修改name
<Button onPress={() => update_age('200')} title='Update Age'/>
<Button onPress={() => update_address('sx')} title='Update Address'/>
</View>
);
}
}
}
组件属性加类型限制
添加依赖prop-types
npm install prop-types
propTypes.js: 创建自定义类型限制
import PropTypes from 'prop-types';
export const map_component = PropTypes.shape({
name: PropTypes.string.isRequired,
info: PropTypes.shape({
age: PropTypes.string.isRequired,
address: PropTypes.string.isRequired,
}).isRequired,
});
修改component/MapComponent.jsx
import PropTypes from 'prop-types';
import * as propTypes from './propTypes';
MapComponent.propTypes =
{
client : PropTypes.any.isRequired, //任意类型
map : propTypes.map_component.isRequired, //自定义限制
fetchState : PropTypes.bool.isRequired, //bool
update_name : PropTypes.func.isRequired,//函数
update_age : PropTypes.func.isRequired,//函数
update_address: PropTypes.func.isRequired,//函数
};
创建客户端
客户端一般用于处理异步函数,比如调用接口
store添加到客户端
Client.js
//store添加到客户端之后客户端就可以获取store的状态以及调用dispatch方法
let store;
export default class Client
{
static init(data)
{
store = data.store;
}
}
App.tsx
import Client from './Client';
Client.init({ store });
创建客户端
Client.js
export default class Client
{
_url;
constructor(
{
url,
}
)
{
this._url = url;
}
}
App.tsx
let client = new Client({ url: 'www.google.com' });
客户端添加到上下文
App.tsx
import Context from './Context';//获取Context
//Context.Provider设置客户端到上下文中
return (
<Provider store={store}>
<Context.Provider value={client}>
</Context>
</Provider>)
客户端映射到组件属性
修改Context.js
import React from 'react';
const Context = React.createContext(null); //创建Context
export default Context;
export function withContext(Component)
{
//从Context上下文中获取客户端并映射到组件的属性中
return (props) => (
<Context.Consumer>
{(client) => <Component {...props} client={client} />}
</Context.Consumer>
);
}
创建客户端方法
修改Client.js
import * as stateAction from './redux/stateAction';
export default class Client
{
getMap(){
store.dispatch(this.getMapData());//dispatch异步方法,在store必须配置thunk才能使用
}
getMapData(){
//dispatch异步方法,返回一个方法,方法的参数是store的dispatch和state,结果类型是Promise
return async (dispatch, getState) => {
dispatch(stateAction.set_fetch_state(false));//设置正在获取数据状态为false
let data=await new Promise((resolve, reject) => { //异步方法获取需要展示的数据
setInterval(() => {
resolve({
name: 'John Doe',
info: {
age: '30',
address: '123 Main St',
},
});
}, 1000);
});
dispatch(stateAction.init_state(data)); //设置需要展示的数据
dispatch(stateAction.set_fetch_state(true));//设置正在获取数据状态为true
};
}
}
组件中使用客户端方法
class MapComponent extends React.Component {
//当组件挂载前执行
componentDidMount() {
const { client } = this.props; //从属性中获取客户端
client.getMap(); //调用dispatch异步方法获取数据并更新ui
}
}
组件效果展示
添加组件到ui
App.tsx
import MapComponent from './component/MapComponent';
return (
<Provider store={store}>
<Context.Provider value={client}>
<MapComponent/>
</Context>
</Provider>)
测试
1s后加载完成
点击按钮后Name,Age,Address变更