1. react所有的生命週期函式
https://react.docschina.org/docs/react-component.html
掛載
當元件例項被建立並插入 DOM 中時,其生命週期呼叫順序如下:
-
constructor()
-
static getDerivedStateFromProps()
-
render()
-
componentDidMount()
更新
當元件的 props 或 state 發生變化時會觸發更新。元件更新的生命週期呼叫順序如下:
-
static getDerivedStateFromProps()
-
shouldComponentUpdate()
-
render()
-
getSnapshotBeforeUpdate()
-
解除安裝
當元件從 DOM 中移除時會呼叫如下方法:
-
componentWillUnmount()
2. 常用的生命週期方法
建立階段
constructor
作用: (1) 獲取props (2) 初始化state
render
作用:渲染元件到頁面中,無法獲取頁面中的DOM物件
componentDidMount()
(1) 元件已經掛載到頁面中 (2) 可以進行DOM操作,比如:獲取到元件內部的DOM物件 (3) 可以傳送請求獲取資料 (4) 可以透過 setState() 修改狀態的值 注意:在這裡修改狀態會重新渲染
執行和互動階段
componentDidUpdate(prevProps, prevState)
作用:元件已經被更新 引數:舊的屬性和狀態物件
解除安裝階段
componentWillUnmount()
元件解除安裝期間,只有一個函式,這個函式也有一個顯著的特點:元件一輩子只能執行一次 使用說明 只要元件不再被渲染到頁面中,那麼這個方法就會被呼叫( 渲染到頁面中 -> 不再渲染到頁面中 )
作用:在解除安裝元件的時候,執行清理工作,比如清除定時器
講解用案例程式碼
子元件
// 子元件 class Child extends Component { //構造方法 constructor() { console.log('Child-constructor'); super() this.state = { parentMsg: '父元件的資料' } } // 元件掛載後 componentDidMount(){ console.log('Child-componentDidMount'); } // 是否應該更新元件 shouldComponentUpdate(){ console.log('Child-shouldComponentUpdate'); return true } // 元件更新後 componentDidUpdate(){ console.log('Child-componentDidUpdate'); } // 元件解除安裝前 componentWillUnmount(){ console.log('Child-componentWillUnmount'); } //元件渲染 render() { console.log('Child-render'); return ( <div> <p>子元件------------------{this.state.parentMsg}</p> </div> ); } }
父元件
// 父元件 class App extends Component { // 構造方法 constructor() { console.log('App-constructor'); super() this.state = { parentMsg: '父元件的資料' } } // 元件掛載後 componentDidMount(){ console.log('App-componentDidMount'); } // 是否應該更新元件 shouldComponentUpdate(){ console.log('App-shouldComponentUpdate'); return true } // 元件更新後 componentDidUpdate(){ console.log('App-componentDidUpdate'); } // 元件解除安裝前 componentWillUnmount(){ console.log('App-componentWillUnmount'); } change = ()=>{ this.setState({ parentMsg: '新的新的' }) } //元件渲染 render() { console.log('App-render'); return ( <div> <p>父元件-------------------{this.state.parentMsg}</p> <Child msg={this.state.parentMsg}></Child> <p><button onClick={this.change}>改變父元件的資料</button></p> </div> ); } }
npm i react-router-dom -S
import React from 'react //引入路由中的各種API import { HashRouter, BrowserRouter, Routes, Route, Navigate, Link, NavLink, Outlet } from 'react-router-dom' // 引入路由相關元件 import Home from './Home' import Cart from './Cart' import My from './My' import NotFound from './NotFound' import FooterNav from './FooterNav' import Tv from './home/Tv' import Ai from './home/Ai' import Login from './Login' export default function App() { return ( <BrowserRouter> <Routes> <Route path="/home" element={<Home></Home>}> <Route path="tv" element={<Tv></Tv>}></Route> <Route path="ai" element={<Ai></Ai>}></Route> </Route> <Route path="/cart" element={<Cart></Cart>}></Route> <Route path="/login" element={<Login></Login>}></Route> <Route path="/my" element={<My></My>}></Route> <Route path="/" element={<Navigate to="/home"></Navigate>}></Route> <Route path="*" element={<NotFound></NotFound>}></Route> </Routes> <FooterNav></FooterNav> </BrowserRouter> ) }
-
-
BrowserRouter是history模式, 生產版本需要後端進行相應的配置, 路徑前沒有'#',比較美觀
-
HashRouter是hash模式,路由前有'#'
3.2 Routes
<Route path="/cart" element={<Cart></Cart>}></Route>
3.4 Navigate重定向
<Route path="/" element={<Navigate to="/home"></Navigate>}></Route>
<Link to="/movie" >電影</Link>
<NavLink to="/find" class="active">發現</NavLink>
<Route path="/home" element={<Home></Home>}>
<Route path="tv" element={<Tv></Tv>}></Route>
<Route path="ai" element={<Ai></Ai>}></Route>
</Route>
<Route path="/home" element={<Home></Home>}>
<Route index element={<Tv></Tv>}></Route>
<Route path="ai" element={<Ai></Ai>}></Route>
</Route>
4.3 Outlet定義二級路由出口
import React,{useState,useEffect} from 'react' import style from './Home.css' import { Outlet,NavLink,useNavigate} from 'react-router-dom' export default function Home() { return ( <div> <div className="header"> <p><NavLink to="" >電視</NavLink></p> <p><NavLink to="ai" >智慧</NavLink></p> </div> <Outlet></Outlet> </div> ) }
<Route path="/list/:id" element={<List></List>}></Route>
<p><NavLink to="/list/5">列表</NavLink></p>
5.3 獲取動態路由引數
import { useParams } from 'react-router-dom'; ... const params = useParams() console.log(params.id) //5
import { useNavigate,useParams,useSearchParams,useLocation } from 'react-router-dom';
const navigate = useNavigate() //跳轉到/my navigate("/my") //跳轉到上一頁 navigate(-1) //跳轉到/my,並替換當前歷史記錄 navigate("/my",{replace: true}) //攜帶引數 navigate("/my",{replace: true,state:{arr:[1,2,3]}})
6.2 useParams
動態路由
<Route path="/list/:id" element={<List></List>}></Route>
<p><NavLink to="/list/5">列表</NavLink></p>
const params = useParams()
console.log(params.id) //5
import { useSearchParams } from 'react-router-dom'; // 當前路徑為 /foo?id=12 function Foo(){ const [searchParams] = useSearchParams(); console.log(searchParams.get('id')) // 12 return ( <div>foo</div> ) }
-
-
key: "h8dnd0wk"
-
pathname: "/list/5"
-
search: ""
-
state: null
import { useNavigate,useParams,useLocation } from 'react-router-dom'; ... export default function List() { //用navigate實現程式設計式導航 const navigate = useNavigate() //獲取動態路由的引數 const params = useParams() //獲取url資訊 const location = useLocation() const toUrl = ()=>{ // navigate("/my") navigate("/my",{replace: true}) } return ( <div> list <hr /> <button onClick={toUrl}>回到我的</button> </div> ) }
.footerNav { display: flex; justify-content: space-around; position: absolute; width: 100%; height: 60px; left: 0; bottom: 0; background-color: #aaa; } .footerNav .active{ border: 1px solid #000; background-color: #f00; }
import React from 'react' import { Link, NavLink } from 'react-router-dom' import './FooterNav.css' export default function FooterNav() { return ( <div className="footerNav"> <p><NavLink to="/home">首頁</NavLink></p> <p><NavLink to="/cart">購物車</NavLink></p> <p><NavLink to="/my">我的</NavLink></p> <p><NavLink to="/list/5">列表</NavLink></p> </div> ) }
import React from 'react' import { HashRouter,BrowserRouter,Routes, Route,Navigate,Link,NavLink,Outlet} from 'react-router-dom' import Home from './Home' import Cart from './Cart' import My from './My' import NotFound from './NotFound' import FooterNav from './FooterNav' import Tv from './home/Tv' import Ai from './home/Ai' import Login from './Login' import isLogin from './util/token' import List from './List' export default function App() { return ( <BrowserRouter> <Routes> <Route path="/home" element={<Home></Home>}> <Route path="tv" element={<Tv></Tv>}></Route> <Route path="ai" element={<Ai></Ai>}></Route> </Route> <Route path="/cart" element={isLogin() ?<Cart></Cart>:<Login></Login>}></Route> <Route path="/login" element={<Login></Login>}></Route> <Route path="/my" element={<My></My>}></Route> <Route path="/my" element={<My></My>}></Route> <Route path="/list" element={<List></List>}></Route> <Route path="/" element={<Navigate to="/home"></Navigate>}></Route> <Route path="*" element={<NotFound></NotFound>}></Route> </Routes> <FooterNav></FooterNav> </BrowserRouter> ) }
.header { display: flex; justify-content: space-around; } .header .active { border: 1px solid #000; } .header .atdh { background-color: #f00; }
import React,{useState,useEffect} from 'react' import style from './Home.css' import { Outlet,NavLink,useNavigate} from 'react-router-dom' export default function Home() { const navigate = useNavigate(); useEffect(()=>{ navigate('/home/tv') },[])// eslint-disable-line return ( <div> <div className="header"> <p><NavLink to="tv" >電視</NavLink></p> <p><NavLink to="ai" >智慧</NavLink></p> </div> <Outlet></Outlet> </div> ) }
<Route path="/home" element={<Home></Home>}> <Route path="tv" element={<Tv></Tv>}></Route> <Route path="ai" element={<Ai></Ai>}></Route> </Route>
在App.js中透過json資料實現路由配置
import React from 'react' import { BrowserRouter as Router, Navigate, useRoutes } from 'react-router-dom' import Home from './pages/Home' import Category from './pages/Category' import Phone from './pages/Category/Phone' import NoteBook from './pages/Category/NoteBook' import GoodsList from './pages/GoodsList' import My from './pages/My' import Detail from './pages/Detail' import NotFound from './pages/NotFound' const GetAllRoutes = () => { const routes = useRoutes([ { path: '/', element: <Navigate to="/Home" /> }, { path: '/Home', element: <Home /> }, { path: '/Category', element: <Category />, children: [ { //預設路由 index: true, element: <Phone /> }, { path: 'NoteBook', element: <NoteBook /> } ] }, { path: '/GoodsList', element: <GoodsList /> }, { path: '/My', element: <My /> }, { path: '/Detail/:id', element: <Detail /> }, { path: '/404', element: <NotFound /> }, { path: '*', element: <NotFound /> } ]) return routes; } export default function App() { return ( <Router> <GetAllRoutes /> </Router> ) }
import {lazy} from 'react'
const Later = lazy(() => import('./Later'));
import { lazy, Suspense } from 'react'; const Later = lazy(() => import('./Later')); export default function App { return ( <div> <Suspense fallback={<div>loading...</div>}> <Later /> </Suspense> </div> ); }
src/routes/index.js
src/routes/config.js
src/routes/privateRoute.js
/** * PrivateRoute使用方式 * <PrivateRoute element={<Cart>} tag="許可權"> </PrivateRoute> * props: {element:, tag: } */ import { Navigate } from "react-router-dom"; const PrivateRoute = props => { const isLogin = localStorage.getItem("token") return isLogin ? ( (props.element) ) : ( <Navigate to="/login"></Navigate> ); }; export default PrivateRoute;
src/routes/config.js
import PrivateRoute from './privateRoute'; import { Suspense } from 'react'; const WrapperRouteComponent = ({ titleId, auth, ...props }) => { if (titleId) { document.title = titleId } return ( <Suspense fallback={<div>loading...</div>}> {auth ? <PrivateRoute {...props} /> : (props.element)} </Suspense> ) }; export default WrapperRouteComponent;
src/routes/index.js
import { lazy } from 'react'; import Home from '../Home'; import WrapperRouteComponent from './config'; import { useRoutes, Navigate } from 'react-router-dom'; const NotFound = lazy(() => import(/* webpackChunkName: "404'"*/ '../NotFound')); const Ai = lazy(() => import(/* webpackChunkName: "ai'"*/ '../home/Ai')); const Tv = lazy(() => import(/* webpackChunkName: "tv'"*/ '../home/Tv')); const Cart = lazy(() => import(/* webpackChunkName: "Cart'"*/ '../Cart')); const My = lazy(() => import(/* webpackChunkName: "My'"*/ '../My')); const List = lazy(() => import(/* webpackChunkName: "List'"*/ '../List')); const Detail = lazy(() => import(/* webpackChunkName: "Detail'"*/ '../Detail')); const Login = lazy(() => import(/* webpackChunkName: "Login'"*/ '../Login')); const routeList = [ { path: '/', element: <Navigate to="/home" /> }, { path: '/home', // element: <Home />, element: <WrapperRouteComponent element={<Home />} titleId="首頁" />, children: [ { path: 'ai', element: <WrapperRouteComponent element={<Ai />} titleId="ai" />, }, { path: 'tv', element: <WrapperRouteComponent element={<Tv />} titleId="tv" />, } ] }, { path: '/cart', element: <WrapperRouteComponent element={<Cart />} titleId="Cart" auth={true}/>, }, { path: '/my', element: <WrapperRouteComponent element={<My />} titleId="My" /> }, { path: '/list', element: <WrapperRouteComponent element={<List />} titleId="List" /> }, { path: '/detail/:id/:type', element: <WrapperRouteComponent element={<Detail />} titleId="Detail" /> }, { path: '/login', element: <WrapperRouteComponent element={<Login />} titleId="Login" /> }, { path: '/404', element: <NotFound /> }, { path: '*', element: <NotFound /> } ] const RenderRouter = () => { const element = useRoutes(routeList); return element; }; export default RenderRouter;
App.js
import React from 'react' import "./App.css" //引入路由中的各種API import { BrowserRouter as Router, } from 'react-router-dom' import RenderRouter from './routes' import TabBar from './TabBar' export default function App() { return ( <div className="app"> <Router> <RenderRouter></RenderRouter> <TabBar></TabBar> </Router> </div> ) }