路由基本使用
- 安装插件
npm install react-router-dom - /src/index.js ```jsx import React from ‘react’; import ReactDOM from ‘react-dom’; import App from ‘./App’; import {HashRouter} from ‘react-router-dom’
/**
- HashRouter 开启路由
*/
ReactDOM.render(
, document.getElementById(‘root’) );
- src/components/home.js```jsximport React, { Component } from 'react'class Home extends Component {render() {return (<div>Home 首页内容</div>)}}export default Home
- src/components/list.js ```jsx import React, { Component } from ‘react’
class List extends Component { render() { return (
export default List
- src/App.js```jsximport React, {Component} from 'react'import {Link, Route} from 'react-router-dom'import Home from './components/home'import List from './components/list'/*** Link: to 属性指定跳转的链接* Router: path component*/class App extends Component {render() {return (<div><div><Link to='/home'>首页</Link>----<Link to='/list'>列表页</Link></div><hr /><div><Route path='/home' component={Home} /><Route path='/list' component={List} /></div></div>)}}export default App
exact 属性-默认展示内容
- src/App.js
<div><Route path="/" component={Home} exact /><Route path='/home' component={Home} /><Route path='/list' component={List} /></div>
路由匹配规则
- src/App.js ```jsx import React, {Component} from ‘react’ import {Link, Route, Switch} from ‘react-router-dom’ import Home from ‘./components/home’ import List from ‘./components/list’ import NotFound from ‘./components/notFound’
/**
- Link: to 属性指定跳转的链接
- Router: path component */
class App extends Component { render() { return (
export default App
<a name="kWUVs"></a>## 动态路由传参- 路由参数占位符 src/App.js```jsximport Detail from './components/detail'class App extends Component {render() {return (<div><div><Link to='/home'>首页</Link>----<Link to='/list'>列表页</Link></div><hr /><div><Switch><Route path="/" component={Home} exact /><Route path='/home' component={Home} /><Route path='/list' component={List} exact /><Route path="/detail/:id" component={Detail} /><Route component={NotFound} /></Switch></div></div>)}}export default App
- 触发操作的时候传递具体的参数 src/components/list.js ```jsx import React, { Component } from ‘react’ import { Link } from ‘react-router-dom’
class List extends Component { render() { return (
测试文章1
测试文章2
export default List
- 在具体的组件当中使用传递的参数 src/components/detail.js```jsximport React, { Component } from 'react'class Detail extends Component {render(props) {console.log(this.props.match.params.id)return (<div>{this.props.match.params.id}</div>)}}export default Detail
查询参数传参
- src/components/list ```jsx import React, { Component } from ‘react’ import { Link } from ‘react-router-dom’
class List extends Component { render() { return (
测试文章1
测试文章2
测试文章3
export default List
- src/components/home.js```jsximport React, { Component } from 'react'import qs from 'qs'class Home extends Component {render(props) {// console.log(this.props.location.search)console.log(qs.parse(this.props.location.search, {ignoreQueryPrefix: true}))let param = qs.parse(this.props.location.search, {ignoreQueryPrefix: true})return (<div>Home 首页内容 {param.title}</div>)}}export default Home
嵌套路由
- src/components/list.js ```jsx import React, { Component } from ‘react’ import { Link, Route} from ‘react-router-dom’ import Outer from ‘../components/outer’ import Inner from ‘../components/inner’
class List extends Component { render(props) { console.log(this.props) return (
测试文章1
测试文章2
测试文章3
export default List
<a name="jfxqN"></a>## 路由跳转及重定向- src.components/home.js```jsximport { Redirect } from 'react-router-dom'class Home extends Component {render(props) {const isLogin = falseif (!isLogin) {return <Redirect to="/list" />}let param = qs.parse(this.props.location.search, {ignoreQueryPrefix: true})return (<div>Home 首页内容 {param.title}</div>)}}export default Home
路由守卫
src/auth.js ```javascript class Authorized { constructor() { this.authorized = false }
login() { this.authorized = true }
logout() { this.authorized = false }
isAuthorized() { return this.authorized } }
export default new Authorized()
- src/App.js```jsximport auth from './auth'class App extends Component {render() {return (<div><div><Link to='/home'>首页</Link>----<Link to='/list'>列表页</Link></div><hr /><div><Switch><Route path="/" component={Home} exact /><Route path='/home' component={Home} />{/* <Route path='/list' component={List} /> */}<Route path='/list' render={props => {if (auth.isAuthorized()) {// 进入路由return <List {...props} />}else {// 重定向return <Redirect to='/home' />}}} /><Route path="/detail/:id" component={Detail} /><Route component={NotFound} /></Switch></div></div>)}}export default App
src/components/home.js ```jsx import React, { Component } from ‘react’ import qs from ‘qs’ import auth from ‘../auth’ class Home extends Component { login = () => { // 执行登陆 auth.login() alert(‘登陆成功’) } render(props) {
let param = qs.parse(this.props.location.search, {ignoreQueryPrefix: true}) return (
<div><p>Home 首页内容 {param.title}</p><button onClick={this.login}>登陆</button></div>
) } }
export default Home
- src/components/list.js```jsximport { createHashHistory } from 'history'class List extends Component {logout = () => {auth.logout()createHashHistory().push('/home')}render() {console.log(this.props)return (<div><div><button onClick={this.logout}>退出登录</button></div></div>)}}export default List
路由守卫组件
- src/guard.js ```jsx import React,{ Component } from ‘react’ import { Redirect, Route} from ‘react-router’ import auth from ‘./auth’
class AuthRouteGuard extends Component {
render () {
const {component: Component, …rest} = this.props
return (
export default AuthRouteGuard
- src/App.js```jsx<Switch><Route path="/" component={Home} exact /><Route path='/home' component={Home} /><AuthRouteGuard path='/list' component={List} /><Route path="/detail/:id" component={Detail} /><Route component={NotFound} /></Switch>
路由模块懒加载
- 安装插件
npm install @loadable/component - src/App.js ```jsx import loadComponent from ‘@loadable/component’
const Home = loadComponent(() => import(‘./components/home’)) const List = loadComponent(() => import(‘./components/list’)) const NotFound = loadComponent(() => import(‘./components/notFound’)) const Detail = loadComponent(() => import(‘./components/detail’))
<a name="P4Xk2"></a>## 非路由组件传递路由信息- src/components/test.js```jsximport React, { Component } from 'react'import { withRouter } from 'react-router-dom'class Test extends Component {render() {console.log(this.props)return (<div>Test组件</div>)}}export default withRouter(Test)
- src/components/detail.js ```jsx
import Test from ‘./test’ class Detail extends Component { render(props) { return (
{this.props.match.params.id}
export default Detail
<a name="VRazC"></a>##<a name="sK1IB"></a>## useState 设置状态- 什么是 HOOK- 它是一个特殊的函数- 可以让函数组件也具有类组件的特性- 为什么需要 HOOK- 数据共享- 多个业务逻辑代码有可能会存在于同一个生命周期函数中- useState- 一个可以在函数组件中保存状态的 HOOK 函数- 参数: 保存状态的初始值- 返回值- 一个数组- 第一个元素就是当前保存的状态- 第二个就是修改当前保存状态的方法- src/App.js```jsximport React, { useState } from 'react'function App() {const arr = useState(0)const [state, setState] = arrconsole.log(state, setState)return (<div>数据: {state}<button onClick={() => { setState(state + 1) }}>+1</button><button onClick={() => { setState(state - 1) }}>-1</button></div>)}export default App
注意点
- 在函数组件中可以多次使用同一个 HOOK 函数
- 简单类型 复杂
- set操作也是异步的,不能直接修改 state 的元素值 ```jsx import React, { useState } from ‘react’
function App() {
const [ageState, setAgeState] = useState(10) const [nameState, setNameState] = useState(‘zz’) const [personState, setPersonState] = useState({“name”: “jj”, “age”: 20})
const [listState, setListState] = useState([ {name: ‘zoe’, age: 18}, {name: ‘zce’, age: 30}, {name: ‘zzz’, age: 25} ])
// 定义修改第一个 age 值的方法 function incrementAge() { // setAgeState(ageState + 10) // setAgeState(ageState + 10) // setAgeState(ageState + 10) setAgeState((pre) => pre + 10) setAgeState((pre) => pre + 10) setAgeState((pre) => pre + 10) } // 定义修改第二个人物状态 name 的操作 function changeName() { // personState.name = ‘拉钩教育’ setPersonState({…personState, name: ‘拉钩教育’}) } return (
数据:{personState.name}—-{personState.age}
{ listState.map(item => { return (
{item.name}—-{item.age}
) }) }
<a name="AnHjy"></a>## useEffect 使用```jsximport React, { useState, useEffect} from 'react'/*** useEffect* 挂载 更新 卸载*/function Header() {const [strState, setStrState] = useState('拉钩教育')const [numState, setNumState] = useState(10)useEffect(() => {console.log('挂载与更新操作完成了')return () => {console.log('卸载的时候执行')}}, [strState])return (<div><p>{strState} <button onClick={() => {setStrState('大前端')}}>修改字符</button></p><p>{numState} <button onClick={() => {setNumState(numState + 1)}}>修改数值</button></p></div>)}function App() {const [isShow, setIsShow] = useState(true)return (<div>{isShow && <Header />}<hr /><button onClick={() => { setIsShow(!isShow) }}>切换</button></div>)}export default App
优点
import React, { useState, useEffect} from 'react'/*** useEffect* 挂载 更新 卸载*/function Header() {const [strState, setStrState] = useState('拉钩教育')const [numState, setNumState] = useState(10)useEffect(() => {// 事件监听添加操作console.log('事件监听添加操作')return () => {console.log('事件移除监听')}})useEffect(() => {// '发送网络请求获取数据'console.log('发送网络请求获取数据')})useEffect(() => {// 判断是否登录console.log('判断是否登录')})useEffect(() => {console.log('挂载与更新操作完成了')return () => {console.log('卸载的时候执行')}}, [strState])return (<div><p>{strState} <button onClick={() => {setStrState('大前端')}}>修改字符</button></p><p>{numState} <button onClick={() => {setNumState(numState + 1)}}>修改数值</button></p></div>)}function App() {const [isShow, setIsShow] = useState(true)return (<div>{isShow && <Header />}<hr /><button onClick={() => { setIsShow(!isShow) }}>切换</button></div>)}export default App
useContext
import React, { createContext, useContext } from 'react'const UserContext = createContext({})const AreaContext = createContext({})// 定义 Header 组件function Header() {const userInfo = useContext(UserContext)const areaInfo = useContext(AreaContext)return (<div><p>{userInfo.name}</p><p>{userInfo.age}</p><p>{areaInfo.width}</p></div>)}function App() {return (<div><UserContext.Provider value={{ "name": "syy", "age": 18 }}><AreaContext.Provider value={{ "width": 200 }}><Header /></AreaContext.Provider></UserContext.Provider></div>)}export default App
useReducer
import React, { useReducer } from 'react'function reducer(state, action) {switch (action.type) {case 'add':return { ...state, num: state.num + 1 }case 'sub':return { ...state, num: state.num - 1 }default:return { ...state }}}// Homefunction Home() {const [state, dispatch] = useReducer(reducer, { num: 0 })return (<div><p>数据: {state.num}</p><button onClick={() => { dispatch({ type: "add" }) }}>+ 1</button><button onClick={() => { dispatch({ type: "sub" }) }}> - 1</button></div>)}// Aboutfunction About() {const [state, dispatch] = useReducer(reducer, { num: 10 })return (<div><p>数据: {state.num}</p><button onClick={() => { dispatch({ type: "add" }) }}>+ 1</button><button onClick={() => { dispatch({ type: "sub" }) }}> - 1</button></div>)}function App() {return (<div><Home /><About /></div>)}export default App
useCallback
import React, { useState, memo, useCallback} from 'react'// Homefunction Home(props) {console.log('Home组件被渲染了')return (<div><p>Home组件</p><button onClick={() => { props.handler() }}>减小</button></div>)}// Aboutfunction About(props) {console.log('About组件被渲染了')return (<div><p>About组件</p><button onClick={() => { props.handler() }}>增加</button></div>)}const MemoHome = memo(Home)const MemoAbout = memo(About)function App() {console.log('App组件被渲染了')const [numState, setNumState] = useState(10)const [ageState, setAgeState] = useState(20)function increment() {setNumState(numState + 2)}// function decrement() {// setAgeState(ageState - 4)// }//const decrement = useCallback(() => {setAgeState(ageState - 4)}, [ageState])return (<div><p>num数据: {numState}</p><p>age数据: {ageState}</p><hr /><MemoHome handler={decrement} /><hr /><MemoAbout handler={increment} /></div>)}export default App
useMemo
import React, { useState, useMemo } from 'react'function getData() {console.log('getData被调用了')let data = 0for (let i = 0; i < 999; i++) {data += i}return data}function App() {console.log('App组件被渲染了')const [numState, setNumState] = useState(10)const [ageState, setAgeState] = useState(20)const num = useMemo(() => {return getData()}, [])function increment() {setNumState(numState + 10)}return (<div><p>num数据: {numState}</p><p>age数据: {ageState}</p><button onClick={() => { increment() }}>修改</button><p>{num}</p></div>)}export default App
useRef
import React, { useState, useRef } from 'react'/*** 01 useRef 可以用于获取元素* 02 useRef 还可以保存数据* 03 useRef 保存的数据除非我们手动修改,否则的话它是不会改变的*/function App() {const [numState, setNumState] = useState(100)const obj = useRef(numState)return (<div><p>obj当中的 current: {obj.current}</p><p>{numState}</p><button onClick={() => { setNumState(numState + 1) }}>操作</button></div>)}export default App
useImperativeHandle
import React, {useRef, forwardRef, useImperativeHandle } from 'react'function Home(props, oHome) {const oInput = useRef()useImperativeHandle(oHome, () => {return {setValue: () => {oInput.current.value = "Home自己实现的setValue方法"}}})return (<div><h2>Home组件</h2><input ref={oInput}></input></div>)}const ForwardHome = forwardRef(Home)function App() {const oHome = useRef()function btnClick() {console.log(oHome)oHome.current.setValue()}return (<div><ForwardHome ref={oHome} /><button onClick={() => { btnClick() }}>操作input</button></div>)}export default App
useLayoutEffect
import React, { useState, useRef, useEffect, useLayoutEffect } from 'react'import './App.css'function Home() {const oP = useRef()// useEffect(() => {// oP.current.style.left = '0px'// oP.current.style.left = '600px'// console.log('挂载|更新, useEffect')// return () => {// console.log('卸载, useEffect')// }// })// 先于 useEffect 发生useLayoutEffect(() => {oP.current.style.left = '0px'oP.current.style.left = '600px'console.log('挂载|更新, , useLayoutEffect')return () => {console.log('卸载, useLayoutEffect')}})return (<div>home组件<p ref={oP}>Home组件中的 P元素</p></div>)}function App() {const [isShow, setIsShow] = useState(true)return (<div>{isShow && <Home />}<button onClick={() => { setIsShow(!isShow) }}> 切换</button></div>)}export default App
自定义 Hooks
import React, { useState, useEffect } from 'react'// 以 use 开头function useAddEventListener(cName) {useEffect(() => {console.log(cName, '组件挂载|更新添加事件监听')return () => {console.log(cName, '卸载时取消事件监听')}})}function Home() {useAddEventListener('Home---')return (<div>Home组件</div>)}function About() {useAddEventListener('About---')return (<div>About组件</div>)}function App() {const [isShow, setIsShow] = useState(true)return (<div>{isShow && <Home />}{isShow && <About />}<button onClick={() => { setIsShow(!isShow) }}>切换</button></div>)}export default App
