29.9React课程
第05节:react全家桶
(第5节:react全家桶&)
第5节:react全家桶&
App.js
exact精确匹配,可以使用switch独占如果有一个匹配不会继续往下走,一般要与exact配合使用,否则下面不会执行
fallback返回任意jsx语法,增加动态引入与懒加载实现
import React, { Suspense, lazy } from "react";
import logo from "./logo.svg";
import "./App.css";
import {
BrowserRouter as Router,
HashRouter,
Route,
Link,
Switch,
Redirect
} from "react-router-dom";
import ListTest from "./Pages/ListTest";
// import DetailTest from "./Pages/DetailTest";
const DetailTest = lazy(() => import("./Pages/DetailTest"));
function Index(props) {
console.log(props);
return <h2>首页</h2>;
}
function Nav({ history, location }) {
console.log(history, location);
return <h2>导航</h2>;
}
function Test404() {
return <h2>404</h2>;
}
//实现加强版本的route
function UpRoute({ component: Component, isLogin, ...rest }) {
return (
<Route
{...rest}
render={props => {
return isLogin ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: "/login" }} />
);
}}
></Route>
);
}
function Login() {
return <h2>Login</h2>;
}
function Test(props) {
console.log(props);
return (
<div>
<h2>守卫内容</h2>
</div>
);
// return <div>
// {
// props.isLogin ? Component : <Redirect to={{pathname:"/login"}}/>
// }
// </div> ;
}
function App() {
return (
<Router>
<div className="App">
<h1>React-router</h1>
<ul>
<li>
<Link to="/">首页</Link>
</li>
<li>
<Link to="/nav">菜单1</Link>
</li>
<li>
<Link to="/list">列表</Link>
</li>
<li>
<Link to="/detail/10001">详情</Link>
</li>
<li>
<Link to="/test">守卫测试</Link>
</li>
</ul>
</div>
<div>
{/* 路由配置 */}
<Switch>
{/* 首页 /nav */}
{/* switch 一般都会和exact属性配合使用 */}
<Route exact path="/" component={Index}></Route>
<Route exact path="/nav" component={Nav}></Route>
{/* 完全匹配 */}
{/* /list */}
{/* /list/react */}
{/* /list/vue */}
{/* /list/node */}
<Route path="/list" component={ListTest}></Route>
<Route exact path="/detail/:id" component={DetailTest}></Route>
<UpRoute path="/test" component={Test} isLogin={false}></UpRoute>
<Route exact path="/login" component={Login}></Route>
<Route component={Test404}></Route>
</Switch>
{/* <Suspense fallback={<div>Loading....</div>}>
<Route exact path="/detail/:id" component={DetailTest}></Route>{" "}
</Suspense> */}
</div>
</Router>
);
}
export default App;
history是h5对象的api
import React, { Component } from "react";
function DetailTest({ history, location, match }) {
console.log(match, location);
return <h2>宝贝ID:{match.params.id}</h2>;
}
export default DetailTest;
import React, { Component } from "react";
import { Link, Route } from "react-router-dom";
function ReactPage() {
return <h2>ReactPage</h2>;
}
function VuePage() {
return <h2>VuePage</h2>;
}
function NodePage() {
return <h2>NodePage</h2>;
}
function ListTest() {
return (
<div>
<h2>ListTest</h2>
<ul>
<li>
<Link to="/list/react">React</Link>
</li>
<li>
<Link to="/list/vue/">vue</Link>
</li>
<li>
<Link to="/list/node/">node</Link>
</li>
</ul>
<div style={{ border: "1px red solid" }}>
<Route exact path="/list/react" component={ReactPage}></Route>
<Route exact path="/list/vue/" component={VuePage}></Route>
<Route exact path="/list/node/" component={NodePage}></Route>
</div>
</div>
);
}
export default ListTest;
动态路由要完全匹配,点击list进入ListTest去匹配,去加载子路由
有子路由并且是动态匹配,不能对一级路由设置exact
(404页面&)
404页面&
没有任何url匹配输出404,采用漏斗策略
(路由守卫&)
路由守卫&
...rest其他加强属性,小写component jsx不会当做一个组件,要重新起别名
重定向跳转回退不了,其他跳转可以回退。
import React, { Suspense, lazy } from "react";
import logo from "./logo.svg";
import "./App.css";
import {
BrowserRouter as Router,
HashRouter,
Route,
Link,
Switch,
Redirect
} from "react-router-dom";
import ListTest from "./Pages/ListTest";
// import DetailTest from "./Pages/DetailTest";
const DetailTest = lazy(() => import("./Pages/DetailTest"));
function Index(props) {
console.log(props);
return <h2>首页</h2>;
}
function Nav({ history, location }) {
console.log(history, location);
return <h2>导航</h2>;
}
function Test404() {
return <h2>404</h2>;
}
//实现加强版本的route
function UpRoute({ component: Component, isLogin, ...rest }) {
return (
<Route
{...rest}
render={props => {
return isLogin ? (
<Component {...props} />
) : (
<Redirect to={{ pathname: "/login" }} />
);
}}
></Route>
);
}
function Login() {
return <h2>Login</h2>;
}
function Test(props) {
console.log(props);
return (
<div>
<h2>守卫内容</h2>
</div>
);
// return <div>
// {
// props.isLogin ? Component : <Redirect to={{pathname:"/login"}}/>
// }
// </div> ;
}
function App() {
return (
<Router>
<div className="App">
<h1>React-router</h1>
<ul>
<li>
<Link to="/">首页</Link>
</li>
<li>
<Link to="/nav">菜单1</Link>
</li>
<li>
<Link to="/list">列表</Link>
</li>
<li>
<Link to="/detail/10001">详情</Link>
</li>
<li>
<Link to="/test">守卫测试</Link>
</li>
</ul>
</div>
<div>
{/* 路由配置 */}
<Switch>
{/* 首页 /nav */}
{/* switch 一般都会和exact属性配合使用 */}
<Route exact path="/" component={Index}></Route>
<Route exact path="/nav" component={Nav}></Route>
{/* 完全匹配 */}
{/* /list */}
{/* /list/react */}
{/* /list/vue */}
{/* /list/node */}
<Route path="/list" component={ListTest}></Route>
<Route exact path="/detail/:id" component={DetailTest}></Route>
<UpRoute path="/test" component={Test} isLogin={false}></UpRoute>
<Route exact path="/login" component={Login}></Route>
<Route component={Test404}></Route>
</Switch>
{/* <Suspense fallback={<div>Loading....</div>}>
<Route exact path="/detail/:id" component={DetailTest}></Route>{" "}
</Suspense> */}
</div>
</Router>
);
}
export default App;
通过render可以接收函数组件,给Test属性传递其他的属性
创建PrivateRoute
function PrivateRoute({ component: Component, isLogin,
...rest }) {
// 单独解构出component和isLogin
// component为渲染⽬标组件,isLogin通常来⾃Redux
// rest为传递给Route的属性
return (
<Route
{...rest}
render={
锦绣课堂-React课程
props => // props包含match等信息直接传给⽬标组件
isLogin ? ( // 若登陆渲染⽬标组件
<Component {...props} />
) : ( // 未登录重定向到Login
<Redirect
to={{
pathname: "/login",
state: { redirect: props.location.pathname
} // 重定向地址
}}
/>
)
}
/>
);
}
创建Login
function Login({ location, isLogin, login }) {
const redirect = location.state.redirect || "/"; // 重定向
地址
if (isLogin) return <Redirect to={redirect} />;
return (
<div>
<p>登录</p>
<hr />
<button onClick={login}>登录</button>
</div>
);
}
配置路由,ReduxTest
<PrivateRoute path="/management" component={ProductMgt} />
<Route path="/login" component={Login} />
给PrivateRoute传递isLogin={true}试试
整合redux,获取和设置登录态,创建./store/user.js
const initialState = { isLogin: false, loading: false
};
export default (state = initialState, action) => {
switch (action.type) {
case "requestLogin":
return { isLogin: false, loading: true };
case "loginSuccess":
return { isLogin: true, loading: false };
case "loginFailure":
return { isLogin: false, loading: false };
default:
return state;
}
};
export function login(user) {
return dispatch => {
dispatch({ type: "requestLogin" });
setTimeout(() => {
dispatch({ type: "loginSuccess" });
}, 1000);
};
}
引入,store/index.js
import user from "./user";
const store = createStore(
combineReducers({ user }),
applyMiddleware(logger, thunk)
);
连接状态,ReduxTest.js
import { login } from "./store/user.redux";
const PrivateRoute = connect(state => ({
isLogin: state.user.isLogin
}))(function({ isLogin, ...rest }) {})
const Login = connect(
state => ({
isLogin: state.user.isLogin
}),
{ login }
)(function({ isLogin, login }) {})