1.umi和dva集成
2.非父子组件进行通信----同步
需求:city组件中点击城市名,能传到cinema组件,它们不是父子组件,如何通信呢
先创建models文件夹,创建cityModel.ts
在city组件发起dispatch
Cinema组件中可以拿到状态,并修改城市名
代码:
cityModel.ts
export default {
namespace: 'city', //命名空间,不写的话默认是cityModel
state: {
//初始默认值
cityName: '北京',
cityId: 110100,
},
reducers: {
changeCity(prevState: any, action: any) {
// debugger;
console.log(action);
// reducers必须有返回值
return {
...prevState,
cityName: action.payload.cityName,
cityId: action.payload.cityId,
};
},
},
};
City.tsx
import React, { useEffect, useState } from 'react';
import {connect} from 'dva'
import { IndexBar, List } from 'antd-mobile';
import { useHistory } from 'umi';
function City(props) {
const [list, setList] = useState([]);
const history = useHistory();
function filterCity(cities: any) {
// console.log(cities);
// 26个字母
const letterArr: Array<string> = []; //字符串类型
// 二维数组
const newList: any = [];
for (var i = 65; i < 91; i++) {
letterArr.push(String.fromCharCode(i));
}
// console.log(letterArr);
for (var j in letterArr) {
// console.log(cities.filter((item:any)=>item.pinyin.substring(0, 1).toUpperCase()==="A"));
var cityitems: any = cities.filter(
(item: any) =>
item.pinyin.substring(0, 1).toUpperCase() === letterArr[j],
);
// 比如字母O无对应城市,cityitems为空数组 长度为0为假,就不放进newList数组
cityitems.length &&
newList.push({
title: letterArr[j],
items: cityitems,
});
}
// console.log(newList);
return newList;
}
useEffect(() => {
fetch('https://m.maizuo.com/gateway?k=2777578', {
headers: {
'X-Client-Info':
'{"a":"3000","ch":"1002","v":"5.2.0","e":"16460383564094280654127105","bc":"330100"}',
'X-Host': ' mall.film-ticket.city.list',
},
})
.then((res) => res.json())
.then((res) => {
// console.log(res.data.cities);
setList(filterCity(res.data.cities));
});
}, []);
function changeCity(item: any) {
console.log(item.name, item.cityId);
// 修改store state中的状态
props.dispatch({
type:'city/changeCity',//city是model命名空间,changeCity是reducers里的
payload:{
cityName:item.name,
cityId:item.cityId
}
})
history.push('./cinema');
}
return (
<div>
<div style={{ height: window.innerHeight }}>
<IndexBar style={{ height: '100%' }}>
{list.map((group: any) => {
const { title, items } = group;
return (
<IndexBar.Panel index={title} title={title} key={title}>
<List>
{items.map((item: any, index: number) => (
<List.Item
key={index}
onClick={() => {
changeCity(item);
}}
>
{item.name}
</List.Item>
))}
</List>
</IndexBar.Panel>
);
})}
</IndexBar>
</div>
</div>
);
}
// 加了一个小括号()代表返回的是一个空对象,如果只有{}会被认为是无返回值的函数
// 被connect包装后才有dispatch
export default connect(()=>({}))(City)
Cinema.tsx
import React from 'react';
import { connect } from 'dva';
import { NavBar } from 'antd-mobile';
import { SearchOutline } from 'antd-mobile-icons';
function Cinema(props: any) {
// console.log(props);
return (
<div>
<NavBar
onBack={() => {
// console.log('click');
props.history.push('/city');
}}
backArrow={false}
back={props.cityName}
right={<SearchOutline />}
>
标题
</NavBar>
</div>
);
}
// 本质是city修改状态之后,Cinema的父组件connect监听到,再以父传子传给Cinema组件
// connect组件必须返回值,Cinema组件才能拿到值
export default connect((state:any) => {
console.log(state, 26);
return {
cityName: state.city.cityName,
cityId: state.city.cityId,
};
})(Cinema);
3.异步
需求:将影院组件的数据进行缓存,如果是第一次进入该页面就走异步请求数据,再次进就走缓存
可以看到第二次进入cinema页面,控制台的Network里也没有发起Ajax请求,一直是这三个
1.之前id都写死了,每次返回的都是北京的数据,修改好了
并且要写成模板字符串,才能写cityId
2.切换城市不走缓存 清空list
代码
Cinema.ts
import React, { useEffect } from 'react';
import { connect } from 'dva';
import { NavBar } from 'antd-mobile';
import { SearchOutline } from 'antd-mobile-icons';
function Cinema(props: any) {
// console.log(props);
useEffect(()=>{
// 判断是否有数据,没有数据发起请求
if(props.list.length===0){
props.dispatch({
type:"cinema/getList",
payload:{
cityId:props.cityId
}
})
}else{
// 有数据走缓存
console.log('缓存');
}
},[])
return (
<div>
<NavBar
//每次切换城市时不走缓存 清空cinema的list
onBack={() => {
// console.log('click');
props.dispatch({
type:"cinema/clearList"
})
props.history.push('/city');
}}
backArrow={false}
back={props.cityName}
right={<SearchOutline />}
>
标题
</NavBar>
<ul>
{
props.list.map((item:any)=><li key={item.cinemaId}>{item.name}</li>)
}
</ul>
</div>
);
}
{/* 本质是city修改状态之后,Cinema的父组件connect监听到,再以父传子传给Cinema组件
connect组件必须返回值,Cinema组件才能拿到值 */}
export default connect((state:any) => {
console.log(state, 26);
return {
cityName: state.city.cityName,
cityId: state.city.cityId,
list:state.cinema.list
};
})(Cinema);
cinemaModel.ts
export default {
state:{
list:[]
},
namespace: 'cinema',
reducers: {
changeList(prevState:any,action:any){
return{...prevState,list:action.payload}
},
clearList(prevState:any,action:any){
return{...prevState,list:[]}
}
},
effects: {
*getList(action: any, obj: any): any {
const { call, put } = obj;
// call(promise对象)
var res = yield call(getListCinema,action.payload.cityId);
// console.log(res,'getlist--res');
yield put({
type: 'changeList',
payload: res,
});
},
},
};
async function getListCinema(cityId:any) {
// console.log(cityId);
var res = await fetch(
`https://m.maizuo.com/gateway?cityId=${cityId}&ticketFlag=1&k=7703443`,
{
headers: {
'X-Client-Info':
' {"a":"3000","ch":"1002","v":"5.2.0","e":"16460383564094280654127105","bc":"110100"}',
'X-Host': 'mall.film-ticket.cinema.list',
},
},
).then((res) => res.json());
// console.log(res,'res');
return res.data.cinemas;
}