1.dva安装
2.路由
关键代码
router.js
import React from "react";
import { Router, Route, Switch, Redirect } from "dva/router";
// import IndexPage from './routes/IndexPage';
import App from "./routes/App";
import Cinema from "./routes/Cinema";
import Center from "./routes/Center";
import Film from "./routes/Film";
function RouterConfig({ history }) {
return (
<Router history={history}>
<Switch>
{/* <Route path="/" exact component={IndexPage} /> */}
{/* <Route path="/" component={App}></Route> */}
{/* 用render写法,这样App组件里可以写路由 */}
<Route
path="/"
render={() => (
// APP外面不能包{},不然会被识别为表达式(jsx语法),如果写{} App前面要加个return,return <App></App>
<App>
{/* 这里如果不加Switch组件在匹配到film不会停又会因为重定向匹配到film而报错,而且假如在center页面,刷新的话又会回到film页面
路由是模糊匹配的,加exact才是精准匹配,由于默认是模糊匹配,所以匹配到film也不会停,而 Switch保证只能匹配一个
*/}
<Switch>
<Route path={"/film"} component={Film}>
Film
</Route>
<Route path={"/cinema"} component={Cinema}>
Cinema
</Route>
<Route path={"/center"} component={Center}>
Center
</Route>
<Redirect from={"/"} to={"/film"}></Redirect>
</Switch>
</App>
)}
></Route>
</Switch>
</Router>
);
}
export default RouterConfig;
Tabbar.js
import React from "react";
import { NavLink, Switch } from "dva/router";
import "./Tabbar.css";
export default function Tabbar() {
return (
// 选项卡组件
<div>
<footer>
<ul>
{/* 重复点击选项卡同样的内容会有警告,所以要加上Switch标签 */}
<li>
<NavLink activeClassName="active" to={"/film"}>
film
</NavLink>
</li>
<li>
<NavLink activeClassName="active" to={"/cinema"}>
cinema
</NavLink>
</li>
<li>
<NavLink activeClassName="active" to="/center">
center
</NavLink>
</li>
</ul>
</footer>
</div>
);
}
Tabbar.css
footer {
position: fixed;
bottom: 0;
width: 100%;
height: 50px;
line-height: 50px;
/* align-items: center; */
text-align: center;
background-color: white;
}
footer>ul{
list-style: none;
display: flex;
}
footer>ul>li{
flex:1
}
.active{
color: red;
}
3.编程式导航和withRouter用法
编程式导航适合从一个页面携带参数跳转到另一个页面
组件首字母一定是大写,这里我没注意出错了
props有history属性,是因为组件被Route包裹着,Route赋予的属性
用框架已经封装好的方法请求数据
router.js
import React from "react";
import { Router, Route, Switch, Redirect } from "dva/router";
// import IndexPage from './routes/IndexPage';
import App from "./routes/App";
import Cinema from "./routes/Cinema";
import Center from "./routes/Center";
import Film from "./routes/Film";
import Detail from "./routes/Detail";
import Login from "./routes/Login";
function RouterConfig({ history }) {
return (
<Router history={history}>
<Switch>
<Route path={"/login"} component={Login} />
{/* <Route path="/" exact component={IndexPage} /> */}
{/* <Route path="/" component={App}></Route> */}
{/* 用render写法,这样App组件里可以写路由 */}
<Route
path="/"
render={() => (
// APP外面不能包{},不然会被识别为表达式(jsx语法),如果写{} App前面要加个return,return <App></App>
<App>
{/* 这里如果不加Switch组件在匹配到film不会停又会因为重定向匹配到film而报错,而且假如在center页面,刷新的话又会回到film页面
路由是模糊匹配的,加exact才是精准匹配,由于默认是模糊匹配,所以匹配到film也不会停,而 Switch保证只能匹配一个
*/}
<Switch>
<Route path={"/film"} component={Film} />
<Route path={"/cinema"} component={Cinema} />
<Route path={"/center"} render={()=>
localStorage.getItem("token")? <Center/>:<Redirect to={"./login"}></Redirect>
} />
{/* :myid动态路由占位符 */}
<Route path={"/detail/:myid"} component={Detail} />
<Redirect from={"/"} to={"/film"}></Redirect>
</Switch>
</App>
)}
></Route>
</Switch>
</Router>
);
}
export default RouterConfig;
Detail.js
import React, { Component } from 'react'
export default class Detail extends Component {
componentDidMount(){
// 接收上个页面传来的id,利用此id取数据
console.log(this.props.match.params.myid);
}
render() {
return (
<div>Detail</div>
)
}
}
Film.js
import React, { Component } from "react";
// 导入dva封装好的文件
import request from "../utils/request";
export default class Film extends Component {
state={
list:[]
}
componentDidMount() {
request(
"https://m.maizuo.com/gateway?cityId=330100&pageNum=1&pageSize=10&type=1&k=9105921",
{
headers: {
"X-Client-Info":
'{"a":"3000","ch":"1002","v":"5.2.0","e":"16460383564094280654127105","bc":"330100"}',
"X-Host": "mall.film-ticket.film.list",
},
}
).then(res=>
// console.log(res.data.data.films)
this.setState({list:res.data.data.films})
);
}
render() {
return this.state.list.map((item) => (
<li key={item.filmId} onClick={()=>{
// console.log(this.props);
// props上有history属性,组件被Route所包裹着,是Route赋予的属性
this.props.history.push(`/detail/${item.filmId}`)
}}>
<img src={item.poster} style={{ width: "100px" }} />
<p>{item.name}</p>
</li>
));
}
}
4.路由拦截
进入center页面必须有token信息,若没有跳转到登录login页面
router.js
import React from "react";
import { Router, Route, Switch, Redirect } from "dva/router";
// import IndexPage from './routes/IndexPage';
import App from "./routes/App";
import Cinema from "./routes/Cinema";
import Center from "./routes/Center";
import Film from "./routes/Film";
import Detail from "./routes/Detail";
import Login from "./routes/Login";
function RouterConfig({ history }) {
return (
<Router history={history}>
<Switch>
<Route path={"/login"} component={Login} />
{/* <Route path="/" exact component={IndexPage} /> */}
{/* <Route path="/" component={App}></Route> */}
{/* 用render写法,这样App组件里可以写路由 */}
<Route
path="/"
render={() => (
// APP外面不能包{},不然会被识别为表达式(jsx语法),如果写{} App前面要加个return,return <App></App>
<App>
{/* 这里如果不加Switch组件在匹配到film不会停又会因为重定向匹配到film而报错,而且假如在center页面,刷新的话又会回到film页面
路由是模糊匹配的,加exact才是精准匹配,由于默认是模糊匹配,所以匹配到film也不会停,而 Switch保证只能匹配一个
*/}
<Switch>
<Route path={"/film"} component={Film} />
<Route path={"/cinema"} component={Cinema} />
<Route path={"/center"} render={()=>
localStorage.getItem("token")? <Center/>:<Redirect to={"./login"}></Redirect>
} />
{/* :myid动态路由占位符 */}
<Route path={"/detail/:myid"} component={Detail} />
<Redirect from={"/"} to={"/film"}></Redirect>
</Switch>
</App>
)}
></Route>
</Switch>
</Router>
);
}
export default RouterConfig;
Login.js
import React, { Component } from 'react'
export default class Login extends Component {
render() {
return (
<div>Login</div>
)
}
}
Center.js
import React, { Component } from "react";
import { withRouter } from "dva/router";
export default class Center extends Component {
render() {
return (
<div>
Center
{/* <Child props={this.props} /> */}
{/* 不传props的情况下可以使用withRouter */}
<WithChild />
</div>
);
}
}
class Child extends Component {
render() {
return (
<div>
<button
onClick={() => {
// console.log(this.props)
localStorage.removeItem("token");
this.props.history.push("/login");
}}
>
退出登录
</button>
</div>
);
}
}
// 组件首字母要大写,注意
const WithChild = withRouter(Child);
点击退出登录后,token被移除,会跳转到login页面
在控制台我们再设置token数据,并刷新,点击center又可以跳转到center了