React 核心 Hooks & 路由

React的Hooks跟路由的使用

  • React hooks
    • React hooks是什么?
    • React Hooks的优势?
    • 为什么使用 Hooks?
    • 常用 hook
      • useState
      • useEffect
      • 代码案例:
    • Hook 使用规则
  • React 路由
    • 路由
    • SPA
    • 前端路由
    • React Router
      • 基于 Web 的 React Router
      • 组件
        • BrowserRouter 组件
        • HashRouter 组件
        • HashRouter与BrowserRouter的区别
        • Route 组件
        • exact
        • Link 组件
        • to 属性
        • NavLink 组件
          • activeStyle
          • activeClassName
        • 传递 props
        • Route : render
        • 动态路由
          • 动态路由铺垫
        • 路由参数
      • hooks (*Router5.0之后出现的*)
        • Switch 组件
        • withRouter 组件(高阶组件,高阶函数,高阶路由)

React hooks

React hooks是什么?

React hooks 是React 16.8中的新增功能。它们使您无需编写类即可使用状态和其他React功能

React Hooks的优势?

  • 简化组件逻辑
  • 复用状态逻辑
  • 无需使用类组件编写

为什么使用 Hooks?

因为函数组件没有生命周期,没有this,没有state

在16.7(beta)当中函数组件一直被当做纯渲染组件使用

常用 hook

  • useState

在函数组件中,我们没有 this,所以我们不能分配或读取 this.state。我们直接在组件中调用 useState Hook

	基本语法:
	import {useState} from "react";
	let [state,setState] = useState(0);
	let [状态的值, 修改状态的方法] = useState(状态的初始值)
  • useEffect

在函数组件中,useEffect Hook 看做 componentDidMountcomponentDidUpdatecomponentWillUnmount 这三个函数的组合

	基本语法:
	import {useEffect} from "react";
	useEffect(() => {
	    console.log('更新或者挂载了');
	    return () => {
	      console.log('卸载了');
	    }
    }, [监听要更新的数据])

代码案例:

// App根组件
import React, { useState } from "react";
import Child from './Child';
// 函数组件
function App() {
  let [data, setName] = useState({
    name: '浩克',
    age: 28
  })
  let [show, setShow] = useState(true)
  return <div>
    {show ? <Child data={data}></Child> : ''}
    <button onClick={() => {
      setName({ name: '疯狂浩克', age: 10 })
    }}>点我</button>
    <button onClick={() => {
      setShow(false)
    }}>卸载</button>
  </div>
}

export default App;
// Child子组件
import React, { useState, useEffect } from "react";
function Child(props) {
  let { data } = props
  let [age, setAge] = useState(8)
  useEffect(() => {
    console.log('组件更新或者挂载了');
    return () => {
      console.log('组件卸载了');
    }
  }, [data.name])
  return <div>
    <h1>name:{data.name}</h1>
    <h1>age:{age}</h1>
    <button onClick={() => {
      setAge(++age)
    }}>+1</button>
  </div>
}
export default Child

Hook 使用规则

  • 只在最顶层使用 Hook
  • 只在 React 函数中调用 Hook
    • React 函数组件中
    • React Hook 中 - 我自己定义 hook 时,可以调用别的hook
  • 所有的 hook 必须 以 use开头

React 路由

路由

当应用变得复杂的时候,就需要分块的进行处理和展示,传统模式下,我们是把整个应用分成了多个页面,然后通过 URL 进行连接。但是这种方式也有一些问题,每次切换页面都需要重新发送所有请求和渲染整个页面,不止性能上会有影响,同时也会导致整个 JavaScript 重新执行,丢失状态。

SPA

Single Page Application : 单页面应用,整个应用只加载一个页面(入口页面),后续在与用户的交互过程中,通过 DOM 操作在这个单页上动态生成结构和内容
优点:

  • 有更好的用户体验(减少请求和渲染和页面跳转产生的等待与空白),页面切换快
  • 重前端,数据和页面内容由异步请求(AJAX)+ DOM 操作来完成,前端处理更多的业务逻辑

缺点:

  • 首次进入处理慢
  • 不利于 SEO

前端路由

前端路由只是改变了 URL 或 URL 中的某一部分,但一定不会直接发送请求,可以认为仅仅只是改变了浏览器地址栏上的 URL 而已,JavaScript 通过各种手段处理这种 URL 的变化,然后通过 DOM 操作动态的改变当前页面的结构

  • URL 的变化不会直接发送 HTTP 请求
  • 业务逻辑由前端 JavaScript 来完成

目前前端路由主要的模式:

  • 基于 URL Hash 的路由
  • 基于 HTML5 History API 的路由

React Router

React Router 提供了多种不同环境下的路由库

  • web
  • native

基于 Web 的 React Router

基于 web 的 React Router 为:react-router-dom

npm安装:

npm i -S react-router-dom

组件

BrowserRouter 组件

基于 HTML5 History API 的路由组件

使用
index.js组件当中引入:

import { BrowserRouter } from 'react-router-dom'
ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('root')
);
HashRouter 组件

基于 URL Hash 的路由组件
使用
index.js组件当中引入:

import { HashRouter} from 'react-router-dom'
ReactDOM.render(
  <HashRouter>
    <App />
  </HashRouter>,
  document.getElementById('root')
);
HashRouter与BrowserRouter的区别
  1. 从页面的地址栏中可以看出HashRouter是包含#号的,而BrowerRouter是包含/号的
  2. BrowerRouter的开启需要后端配置的,类似于Vue中的history模式。HashRouter类型于Vue中的hash模式
Route 组件

通过该组件来设置应用单个路由信息,Route 组件所在的区域就是就是当 URL 与当前 Route 设置的 path 属性匹配的时候,后面 component 将要显示的区域

exact

exact 属性表示路由使用 精确匹配模式,非 exact 模式下 ‘/’ 匹配所有以 ‘/’ 开头的路由

import React, { useState } from 'react';
import { Route } from 'react-router-dom';
import IndexPage from './view';
import AboutPage from './view/about';
import HomePage from './view/home';
import Nav from './component/nav';
function App() {
  const [state, setstate] = useState('initialState')
  return (
    <div>
      {/* link组件  只改变URL */}
      <Nav></Nav>
      {/* path属性 匹配URL */}
      <Route path="/" exact component={IndexPage} />
      <Route path="/about" exact component={AboutPage} />
      <Route path="/about/home" exact component={HomePage} />
    </div>
  );
}

export default App;
Link 组件

Link 组件用来处理 a 链接 类似的功能(它会在页面中生成一个 a 标签),但设置这里需要注意的,react-router-dom 拦截了实际 a 标签的默认动作,然后根据所有使用的路由模式(Hash 或者 HTML5)来进行处理,改变了 URL,但不会发生请求,同时根据 Route 中的设置把对应的组件显示在指定的位置

to 属性

to 属性类似 a 标签中的 href

NavLink 组件

NavLink 与 Link 类似,但是它提供了两个特殊属性用来处理页面导航

activeStyle

当当前 URL 与 NavLink 中的 to 匹配的时候,激活 activeStyle 中的样式

activeClassName

与 activeStyle 类似,但是激活的是 className

import React from "react";
import { NavLink } from "react-router-dom";
export default function Nav() {
  return (<nav>
    <NavLink to="/" exact activeClassName="active" activeStyle={{ color: 'cyan' }}>首页</NavLink>
    <span> | </span>
    <NavLink to="/about" exact activeClassName="active-about" activeStyle={{ color: 'orange' }}>关于</NavLink>
    <span> | </span>
    <NavLink to="/about/home" exact activeClassName="active-home" activeStyle={{ color: 'pink' }}>我的</NavLink>
    <span> | </span>
  </nav>)
}

React 核心 Hooks & 路由_第1张图片

从上面的图片中可以看到,点击那个,对应的那个路由的样式以及class名会显示出来,剩下的另外两个不显示。
注意:exact属性必不可少,如果不写这个属性的话,它的所有样式都会出来
React 核心 Hooks & 路由_第2张图片

传递 props
<Route exact path='/' component={Home}>

如果 Route 使用的是 component 来指定组件,那么不能使用 props

Route : render
<Route exact path='/' render={() => <Home items={this.state.items} />} />

通过 render 属性来指定渲染函数,render 属性值是一个函数,当路由匹配的时候指定该函数进行渲染

动态路由

为了能给处理上面的动态路由地址的访问,我们需要为 Route 组件配置特殊的 path

动态路由铺垫

就是为了给不同的组件传递不同的参数

路由参数
  • history : 历史记录以及路由给我们的一些操作
  • location : 获取当前URL的一些信息
    • pathname : 当前的URL
    • search : 接口参数
    • state : 跳转路由时,传递的参数
  • match : 当前路由匹配的相关规则
    • params : 动态路由传过来的参数

hooks (Router5.0之后出现的)

  • 不在类组件内使用
  • useHistory : 获取History对象
  • useLocation : 获取Location对象
  • useParams : 获取Params
  • useRouteMatch : 获取Match
Switch 组件

该组件只会渲染首个被匹配的组件

  1. index组件
import React from "react";
import { Link, useParams } from "react-router-dom";
export default function IndexPage(props) {
  console.log(useParams());
  return (
    <div>
      <h1>留言列表</h1>
      <Link to="/list/1" >1</Link>
      <span> | </span>
      <Link to="/list/2" >2</Link>
      <span> | </span>
      <Link to="/list/3" >3</Link>
      <span> | </span>
      <Link to="/list/4" >4</Link>
      <span> | </span>
      <Link to="/list/5" >5</Link>
      <span> | </span>
      <Link to="/list/6" >6</Link>
    </div>
  )
}
  1. App组件
import React from 'react';
import { Route, Switch } from 'react-router-dom';
import IndexPage from './view';
function App() {
  return (
    <div>
      <Switch>
        <Route path="/list/:page" exact render={(props) => {
          return <IndexPage {...props} />
        }}></Route>
      </Switch>
    </div>

  );
}
export default App;

React 核心 Hooks & 路由_第3张图片

withRouter 组件(高阶组件,高阶函数,高阶路由)

如果一个组件不是路由绑定组件,那么该组件的 props 中是没有路由相关对象的,虽然我们可以通过传参的方式传入,但是如果结构复杂,这样做会特别的繁琐。幸好,我们可以通过 withRouter 方法来注入路由对象

// AboutPage
import React from "react";
import HomePage from "./home";
export default function AboutPage() {
  return (
    <div>
      <h1>关于</h1>
      <HomePage use={"爱蜜莉雅"}></HomePage>
    </div>
  )
}
// HomePage
import React from "react";
import { withRouter } from "react-router-dom";
function HomePage(props) {
  console.log(props);
  return <h1>我的</h1>
}
export default withRouter(HomePage)
// App
import React from 'react';
import { Route } from 'react-router-dom';
import AboutPage from './view/about';

function App() {
  return (
    <div>
      <Route path="/about" exact component={AboutPage}></Route>
    </div>
  );
}
export default App;

你可能感兴趣的:(react)