react项目搭建create-router-dom,redux详细解说
1.搭建react脚手架
首先选择脚手架,dav-cli,create-react-app,Ant-Design-Pro-cli。脚手架即为代码层次。这里我们选用create-react-app脚手架
打开我们的cmd,window+R输入cmd进入终端,然后安装我们的脚手架项目实例:https://gitee.com/getluoaxios/raect_dom
npm install -g create-react-app
脚手架安装完成后,我们开始创建react新项目,稍微等一下,创建比较慢
create-react-app 名字
进入到当前项目
cd dome-react
启动项目,下面红框包裹的为显示页面的链接
npm start
到此一个基本的脚手架就已经创建好了
目录:
-
node_modules
存放项目依赖的第三方库和模块。这个目录是由 npm 自动生成的,不需要手动管理。 -
public
存放我们的静态资源 -
src
存放项目源代码的目录。这是你主要的开发目录。 -
index
入口文件,react的页面会渲染到index.html,root元素里面 -
package.json
项目的配置文件,包含项目的依赖、脚本、项目元数据等。你可以在这里定义项目的各种设置和依赖。 -
APP.js
这是一个示例组件,作为应用的主要组件。通常,这个文件会包含应用的主要结构和逻辑。
2.React-route-dom路由使用
npm i react-router-dom
路由的基本使用
- 明确好界面中那块是导航区那一块是展示区
- 导航区使用Link不再使用a标签
<Link to="/xxxxx">Demo</Link>
- 展示区写Route标签进行路径的匹配
<Route path='/xxxx' component={Demo}/>
path为路径 component为展示的页面路径
<App>
的最外侧包裹了一个<BrowserRouter>
或<HashRouter>
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {BrowserRouter} from "react-router-dom"
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<App/>
</BrowserRouter>
</React.StrictMode>
);
reportWebVitals();
HashRouter和BrowserRouter一样,只不过HashRoute在url里是有hash值的
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {HashRouter} from "react-router-dom"
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<HashRouter>
<App/>
</HashRouter>
</React.StrictMode>
);
reportWebVitals();
路由组件与一般组件
1.写法不同
一般组件:< Dome />
路由组件:< Route path='/xxxx' component={Demo} />
2.存放位置不同
一般组件:components
路由组件:pages,views
3.接收参数不同
一般组件:组件传什么过来,就接收什么过来
路由组件:接收固定的三个属性值
history:
go: ƒ go(n)
goBack: ƒ goBack()
goForward: ƒ goForward()
push: ƒ push(path, state)
replace: ƒ replace(path, state)
location:
pathname: "/about"
search: ""
state: undefined
match:
params: {}
path: "/about"
url: "/about"
Switch
在React中相同路径可以加载多个组件的,假如你不想,你可以用
Switch
包裹一下Route
,这样即使相同路径下,也只是加载最上面的组件
<Switch>
<Route path="/home/news" component={News}/>
<Route path="/home/massage" component={Message}/>
<Route path="/home/massage" component={Detail}/>
<Redirect to="/home/news"/>
</Switch>
Redirect
在react中我们想在一开始默认加载哪个组件或者路径不适配的时候我们可以用
Redirect
标签,可以给我们重定向加载任何一个组件,但Redirect
一般出现在Route的最下面
<Switch>
<Route path="/home/news" component={News}/>
<Route path="/home/massage" component={Message}/>
<Redirect to="/home/news"/>
</Switch>
路由的嵌套
NavLink组件
假设现在我们需要给予选中路由一个高亮我们可以使用
NavLink
标签,我们可以把他单独封装成一个公用的路由组件
import React, {Component, Fragment} from "react"
import {NavLink} from 'react-router-dom'
import "./MyNavLink.css"
export default class MyNavLink extends Component {
render() {
return (
<Fragment>
<div className="btn-div">
<NavLink activeClassName="active" className="btn-a" {...this.props}/>
</div>
</Fragment>
)
}
}
注意高亮默认在React-Router中是action属性
如果我们想在react项目中,写入多级路由的话,我们需要在
Link,Route以及Redirect
中加入父级路由
父级路由组件
import {Fragment} from "react"
import {Route, Switch, Redirect} from "react-router-dom"
import Title from "./component/Title";
import About from "./pages/About";
import Home from "./pages/Home";
import MyNavLink from "./MyNavLink";
import './App.css';
function App() {
return (
<Fragment>
<Title/>
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to='/home'>Home</MyNavLink>
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/about"/>
</Switch>
</Fragment>
);
}
export default App;
子组件路由
import React, {Component, Fragment} from "react"
import {Switch, Route, Redirect} from 'react-router-dom'
import MyNavLink from "../../MyNavLink";
import Message from "./Message";
import News from "./News";
export default class Home extends Component {
render() {
return (
<Fragment>
<h1>我是Home</h1><br/>
<MyNavLink to="/home/news">News</MyNavLink>
<MyNavLink to="/home/massage">Massage</MyNavLink>
<Switch>
<Route path="/home/news" component={News}/>
<Route path="/home/massage" component={Message}/>
<Redirect to="/home/news"/>
</Switch>
</Fragment>
)
}
}
路由的模糊匹配
<Fragment>
<Title/>
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to='/home/a/b'>Home</MyNavLink>
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/about"/>
</Switch>
</Fragment>
像这样的路由我们多传,虽然路径不匹配但在模糊匹配下可以让react渲染Home组件,但是不可以头路径不正确
例如:
<Fragment>
<Title/>
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to='/a/home'>Home</MyNavLink>
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Home}/>
<Redirect to="/about"/>
</Switch>
</Fragment>
这样前面a/home
是错误的,匹配不到的
路由的严格匹配
假如现在我们不希望进行模糊匹配,严格按照路径的话我们就可以开启严格匹配模式
<Fragment>
<Title/>
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to='/a/home'>Home</MyNavLink>
<Switch>
<Route exact={true} path="/about" component={About}/>
<Route exact path="/home" component={Home}/>
<Redirect to="/about"/>
</Switch>
</Fragment>
路由的参数
传递Params参数
this.state.massageArr.map(item => {
return <li key={item.id}>
<Link to={`/home/massage/detail/${item.id}/${item.title}`}>
{item.title}
</Link>
</li>
})
我们通过数组的映射以及模版字符串的方式传递了两个Params参数
接收Params参数
<Route path="/home/massage/detail/:id/:title" component={Detail}/>
调用Params参数
export default class Detail extends Component {
render() {
const {id, title} = this.props.match.params
const findResult = data.find((_item) => {
return _item.id === id
})
return (
<Fragment>
<ul>
<li>id:{id}</li>
<li>title:{title}</li>
<li>content:{findResult.content}</li>
</ul>
</Fragment>
)
}
}
我们可以通过props里面的match里面封装的params
里面将传递的值解构出来使用
传递Search参数
this.state.massageArr.map(item => {
return <li key={item.id}>
<Link to={`/home/massage/detail?id=${item.id}&title=${item.title}`}>
{item.title}
</Link>
</li>
})
同样我们也传递了两个Search参数,但注意Search参数不需要接收
querystring库
urlencoded编码
key=value&key=value
像这样的编码格式被称为urlencoded
编码格式
利用 querystring转化格式
import qs from "querystring"
qs.stringify() 将对象转化为urlencoded
qs.parse() 将urlencoded转化为js中的对象
调用Search参数
import React, {Component, Fragment} from "react"
import qs from "querystring"
const data = [
{id: "01", content: "你好,宁夏"},
{id: "02", content: "你好,吉林"},
{id: "03", content: "你好,陕西"},
]
export default class Detail extends Component {
render() {
const {search} = this.props.location
const {id, title} = qs.parse(search.slice(1))
const findResult = data.find((_item) => {
return _item.id === id
})
return (
<Fragment>
<ul>
<li>id:{id}</li>
<li>title:{title}</li>
<li>content:{findResult.content}</li>
</ul>
</Fragment>
)
}
}
如果没有这个第三方库我们可以安装
npm i querystring
state参数
this.state.massageArr.map(item => {
return <li key={item.id}>
<Link to={{pathname: "/home/massage/detail", state: {id: item.id, title: item.title}}}>
{item.title}
</Link>
</li>
})
调用state
import React, {Component, Fragment} from "react"
const data = [
{id: "01", content: "你好,宁夏"},
{id: "02", content: "你好,吉林"},
{id: "03", content: "你好,陕西"},
]
export default class Detail extends Component {
render() {
const {id, title} = this.props.location.state
const findResult = data.find((_item) => {
return _item.id === id
})
return (
<Fragment>
<ul>
<li>id:{id}</li>
<li>title:{title}</li>
<li>content:{findResult.content}</li>
</ul>
</Fragment>
)
}
}
编程式路由导航
编程式路由导航push是压栈式的,浏览器可以回退,有保存记录。而replace是覆盖浏览器的栈顶不能回退
replace编程式路由导航
const replaceShow = (id, title) => { this.props.history.replace(`/home/massage/detail/${id}/${title}`)
}
注意只有在路由组件里面才可以使用这两个方法
push编程式路由导航
const pushShow = (id, title) => { this.props.history.push(`/home/massage/detail/${id}/${title}`)
}
withRouter
如果我们想在非路由组件里调用路由组件的方法我们就可以用withRouter
import React, {Component, Fragment} from "react"
import {withRouter} from "react-router-dom"
class Title extends Component {
back = () => {
this.props.history.goBack()
}
forWord = () => {
this.props.history.goForward()
}
render() {
return (
<Fragment>
<h2 style={{marginLeft: "50px"}}>React Router Demo</h2>
<button onClick={this.forWord}>前进</button>
<button onClick={this.back}>后退</button>
<hr/>
</Fragment>
)
}