一、使用create-react-app创建react应用
1.1. react脚手架
1.xxx脚手架: 用来帮助程序员快速创建一个基于xxx库的模板项目
1.包含了所有需要的配置(语法检查、jsx编译、devServer…)
2.下载好了所有相关的依赖
3.可以直接运行一个简单效果
2.react提供了一个用于创建react项目的脚手架库: create-react-app
3.项目的整体技术架构为: react + webpack + es6 + eslint
4.使用脚手架开发的项目的特点: 模块化, 组件化, 工程化
1.2. 创建项目并启动
第一步,全局安装:npm i -g create-react-app
第二步,切换到想创项目的目录,使用命令:create-react-app hello-react
第三步,进入项目文件夹:cd hello-react
第四步,启动项目:npm start
1.3. react脚手架项目结构
public ---- 静态资源文件夹
favicon.icon ------ 网站页签图标
index.html -------- 主页面
logo192.png ------- logo图
logo512.png ------- logo图
manifest.json ----- 应用加壳的配置文件
robots.txt -------- 爬虫协议文件
src ---- 源码文件夹
App.css -------- App组件的样式
App.js --------- App组件
App.test.js ---- 用于给App做测试
index.css ------ 样式
index.js ------- 入口文件
logo.svg ------- logo图
reportWebVitals.js
--- 页面性能分析文件(需要web-vitals库的支持)
setupTests.js
---- 组件单元测试的文件(需要jest-dom库的支持)
二、React路由
路由的理解
2.1、 SPA的理解
1.单页Web应用(single page web application,SPA)。
2.整个应用只有一个完整的页面。
3.点击页面中的链接不会刷新页面,只会做页面的局部更新。
4.数据都需要通过ajax请求获取, 并在前端异步展现。
2.2、路由的理解
1.什么是路由?
1.一个路由就是一个映射关系(key:value)
2.key为路径, value可能是function或component
2.路由分类
后端路由:
1、理解: value是function, 用来处理客户端提交的请求。
2、注册路由: router.get(path, function(req, res))
3、工作过程:当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据
前端路由:
1、浏览器端路由,value是component,用于展示页面内容。
2、注册路由: <Route path="/test" component={Test}>
3、工作过程:当浏览器的path变为/test时, 当前路由组件就会变为Test组件
react路由的使用
react-router-dom的理解
1、react的一个插件库。
2、专门用来实现一个SPA应用。
3、基于react的项目基本都会用到此库。
内置组件
1、<BrowserRouter>
2、<HashRouter>
3、<Route>
4、<Redirect>
5、<Link>
6、<NavLink>
7、<Switch>
下载react-router-dom:npm install --save react-router-dom
BrowserRouter 和 HashRouter 的区别
1.底层原理不一样
BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。HashRouter使用的是URL的哈希值。
2.path表现形式不一样
BrowserRouter的路径中没有#,例如: localhost:3000/demo/test
HashRouter的路径包含#,例如: localhost:3000/#/demo/test
3.刷新后对路由state参数的影响
(1).BrowserRouter没有任何影响,因为state保存在history对象中。
(2).HashRouter刷新后会导致路由state参数的丢失!!!
原生html中,靠<a>跳转 不同的页面
<a href="./about.html">About</a>
<a href="./home.html">Home</a>
在React中靠路由链接实现切换组件
首先我们把about.html和home.html改成两个组件
然后引入 Link 和 Route ,通过<Route>注册路由,通过 <Link />进行切换组件
import {HashRouter, Link , Route} from "react-router-dom";
hash路由模式
<HashRouter>
跳转路由
<Link to="/about" />
<Link to="/home" />
注册路由
<Route path="/about" component={About}></Route>
<Route path="/home" component={Home}></Route>
</HashRouter>
<NavLink>是<Link>的一个特定版本,会在匹配上当前的url的时候给已经渲染的元素添加参数,组件的属性有:
- activeClassName(string):设置选中样式,默认值为active
- activeStyle(object):当元素被选中时,为此元素添加样式
- exact(bool):为true时,只有当导致和完全匹配class和style才会应用
- strict(bool):为true时,在确定为位置是否与当前URL匹配时,将考虑位置pathname后的斜线
- isActive(func)判断链接是否激活的额外逻辑的功能
所以开发中一般使用<NavLink>
路由的基本使用
import { HashRouter, Route, NavLink } from "react-router-dom";
<HashRouter>
跳转路由
<NavLink to="/about" />
<NavLink to="/home" />
注册路由
<Route path="/about" component={About}></Route>
<Route path="/home" component={Home}></Route>
</HashRouter>
Switch和Redirect
当我们注册路由,注册了同样的路径,渲染不同的路由组件,当跳转路由的时候有两个路由能匹配上就会出现两个路由组件全部展示的情况,如下图
<Route path="/home" component={Home}></Route>
<Route path="/home" component={Test}></Route>
image.png
正常来说一个路径匹配一个路由,上图明显有问题,如果每个同样的路径匹配多个路由组件,如果我们要展示两个路由组件为什么不把两个路由组件合成一个组件呢,当第一个路由组件匹配上以后,如果下面还有无数个相同路径的路由组件,会匹配无数次路由会导致性能损耗,所以一个路径匹配一个路由。这个时候我们会使用Switch:Switch实现提高匹配效率的效果,匹配到第一个后面就不会匹配了
<Switch>
<Route path="/about" component={About}></Route>
<Route path="/home" component={Home}></Route>
<Route path="/home" component={Test}></Route>
一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由
<Redirect to="/about" />
</Switch>
image.png
路由的严格模式
image.png如上图,我们注册的路由组件路径和跳转路由的开始的路径能匹配上,就能正常展示路由组件的页面,如下图,跳转的路径是 /home/index,注册路由的地址是 /home,因为跳转路径前面的地址是 /home,默认是模糊模式,所以成功匹配展示注册路由组件
如果需要注册的路由组件路径和跳转路由的开始的路径完全一样:
路由开启严格匹配
严格模式不要随便开启,这样会影响二级路由
<Route exact path="/about" component={About}></Route>第一种方法,写exact属性就行
<Route exact={true} path="/home" component={Home}></Route>第二种方法,写exact={true}
嵌套路由
这里是父组件,正常写路由就行
<Switch>
<Route path="/about" component={About}></Route>
<Route path="/home" component={Home}></Route>
<Redirect to="/about" />
</Switch>
这里是子路由的组件,子路由注册的时候需要加上父组件的路径
<Switch>
<Route path="/home/news" component={News}/>//嵌套路由需要加上父路径
<Redirect to="/home/news"/>
</Switch>
路由传参
跳转路由
向路由组件传递params参数
<Link to={`/home/message/detail/${i.id}/${i.title}`} children={i.title} />
向路由组件传递search参数
<Link to={`/home/message/detail/?id=${i.id}&title=${i.title}`} children={i.title} />
向路由组件传递state参数
<Link to={{pathname: "/home/message/detail", state: {id:i.id,title:i.title}}} children={i.title} />
注册路由
声明接收params参数
<Route path="/home/message/detail/:id/:title" component={Detail} />
search参数无需声明接收,正常注册路由即可
<Route path="/home/message/detail" component={Detail} />
state参数无需声明接收,正常注册路由即可
<Route path="/home/message/detail" component={Detail} />
路由组件接受路由参数
接收params参数
const {id, title} = this.props.match.params;
接收search参数
import qs from "querystring";
const {id, title} = qs.parse((this.props.location.search).slice(1));
接收state参数
const {id, title} = this.props.location.state || {};
接收search参数,需要下载querystring npm i querystring
querystring基本使用
import qs from "querystring";
let obj = { name: 'tom', age: 18}; //name=tom&age=18 key=value&key=value
console.log(qs.stringify(obj));
let str = 'carName=奔驰&price=199';
console.log(qs.parse(str));
路由跳转模式push和replace
push(/path) 里面的path会进入路由栈,
replace(/path) 不会,但是它里面的path会替换掉路由栈里最后一个路由
路由跳转开启replace模式,默认是push模式
<Link to={`/home/message/detail/${i.id}/${i.title}`} replace={true} children={i.title} />
编程式路由
通过按钮触发方法,方法里进行路由跳转
<button onClick={() => this.pushShow(i)}>Push查看</button>
<button onClick={() => this.replaceShow(i)}>Replace查看</button>
注册路由
接收params参数
<Route path="/home/message/detail/:id/:title" component={Detail} />
search参数无需声明接收,正常注册路由即可
<Route path="/home/message/detail" component={Detail} />
state参数无需声明接收,正常注册路由即可
<Route path="/home/message/detail" component={Detail} />
跳转路由
replaceShow = (i) =>{
replace跳转+携带params参数
this.props.history.replace(`/home/message/detail/${i.id}/${i.title}`)
replace跳转+携带search参数
this.props.history.replace(`/home/message/detail?id=${i.id}&title=${i.title}`)
replace跳转+携带state参数
this.props.history.replace(`/home/message/detail`,{...i})
}
pushShow = (i) =>{
push跳转+携带params参数
this.props.history.push(`/home/message/detail/${i.id}/${i.title}`)
push跳转+携带search参数
this.props.history.push(`/home/message/detail?id=${i.id}&title=${i.title}`)
push跳转+携带state参数
this.props.history.push(`/home/message/detail`,{...i})
}
路由组件接受路由参数
接收params参数
const {id, title} = this.props.match.params;
接收search参数
import qs from "querystring";
const {id, title} = qs.parse((this.props.location.search).slice(1));
接收state参数
const {id, title} = this.props.location.state || {};
网友评论