react脚手架基础
1、一些命令
yarn add create-react-app -g
添加脚手架到全局
npm install create-react-app -g
添加脚手架到全局
yarn create-react-app my-demo
创建脚手架
npx create-react-app my-demo
创建脚手架,但是不保存create-react-app到内存
已安装create-react-app时:create-react-app my_react_project
创建脚手架
yarn start
Starts the development server.
启动开发服务器。
开发服务器
yarn build
Bundles the app into static files for production.
将应用程序捆绑到静态文件中用于生产。
打包应用
yarn test
Starts the test runner.
开始测试运行程序。
测试
yarn eject
Removes this tool and copies build dependencies, configuration files
and scripts into the app directory. If you do this, you can’t go back!
删除此工具并复制生成依赖项、配置文件并将脚本放入app目录中。如果你这样做,你就回不去了!
配置各种文件,现在一般不用。高级工程师使用较多
2、简单的结构
public:
index.html
src:
components/person.js
app.js
index.js
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>191121_react_staging</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
person.js
//定义一个展示人员信息的组件
//1.引入React核心库
import React,{Component} from 'react'
//2.定义一个Person组件,随后暴露
export default class Person extends Component{
render(){
return (
<ul>
<li>姓名:海吉</li>
<li>sex:女</li>
</ul>
)
}
}
App.js
//App组件是所有组件的“壳子”
//1.引入react核心库
import React,{Component} from 'react'
//2.引入一些我们自定义的组件
import Person from './components/person'
//3.定义一个名为App的组件,随后暴露
export default class App extends Component{
render(){
return (
<div>
<h2>hello,React脚手架</h2>
<Person/>
</div>
)
}
}
index.js
//该文件是整个应用的入口文件,该文件需要渲染App
//1.引入react核心库
import React from 'react'
//2.引入react-dom库
import ReactDOM from 'react-dom'
//3.引入App
import App from './App'
//4.渲染App到root容器
ReactDOM.render(<App/>,document.getElementById('root'))
3、axios的使用
案例
获取GitHub上以某个字母开头点赞量最高的组件
import React, { Component } from "react";
import axios from "axios";
export default class app extends Component{
state = {
repoName: '',//仓库名称
repoUrl: '',//仓库地址
isLoading: true,//是否正在请求
err: '',//错误信息
keyWord:'r' //以r为搜索条件
}
async componentDidMount() {
const url = `https://api.github.com/search/repositories?q=${this.state.keyWord}&sort=stars`
try {
const result =await axios.get(url)
const { name, html_url } = result.data.items[0]
this.setState({ repoName: name, repoUrl: html_url ,isLoading :false})
} catch (error) {
this.setState({isLoading:false,err:error.message})
}
}
render() {
const { repoName, repoUrl, isLoading, err, keyWord } = this.state
let content = ''
if (isLoading)
content=<h2>Loading</h2>
else if(err)content=<h2>{err}</h2>
else content=<h2>在GitHub上以{keyWord}开头,点赞量最多的是:<a href={repoUrl}>{repoName}</a></h2>
return content
}
}
4、pubsub
要使用消息订阅,必须安装pubsub-js
yarn add pubsub-js
import PubSub from 'pubsub-js'
PubSub.publish(‘方法名’,传递的参数);
例子:
PubSub.publish(‘updateListData’, {isLoading:false,userList:items});
PubSub.subscribe(‘方法名’, (方法名,传递的数据(data))=>{
});
PubSub.subscribe(‘方法名’, (msg,data)=>{
});
注意:msg形参必须存在,(data)模式里data代表的不是参数而是方法名
但是写了而不使用会有警告,所以可以以'_'代替
例子:
PubSub.subscribe(‘updateListData’, (_,stateObj)=>{
this.setState(stateObj)
});
5、路由
Route和Router
生活中:
一、路由(可以上网的一跳线路)?路由器(管理线路的)?
二、关系:路由器是管理一个一个路由的
程序中:
一、路由(Route)、路由器(Router)
路由:key-value组合
1.前端路由:key是你输入的地址,value组件
你如果输入a地址,我就给看A组件
特点:请求不会发给服务器
备注:请求没有到达服务器,被前端路由器所捕获了。
2.后端路由:key是:method-pathname value:function
登录:http://172.45.23.21/login
注册:http://172.45.23.21/register
备注:请求实实在在到达了服务器,返回的数据是服务器定的
二、关系:路由器是管理一个一个路由的(Router里包裹着Route)
Link和NavLink
NavLink和Link都是路由的标签,点击时会根据to的地址对Route标签中的地址和文件进行匹配
注意:link外面必须包裹Router,但是直接写会报错
现在Router已经分为了BrowserRouter和HashRouter
所以使用BrowserRouter或HashRouter
为了方便,通常在主index.jsx中,包裹在<App/>外
<Link to='/home/message'>Message</Link>
<NavLink to='/home/message'>Message</NavLink>
<Route path='/home' component={Home} />
<Route path='/home/message' component={Message} />
NavLink比Link多了点击时的默认active样式
可以通过activeClassName="demo"
这句代码修改默认的样式
BrowserRouter和HashRouter
BrowserRouter
HashRouter
Route和Switch和exact
注意: react中路由的匹配规则和vue不同
react中路由匹配时是模糊匹配
例:
<Link to='/home/message'>Message</Link>
<Route path='/home' component={Home} />
<Route path='/home/message' component={Message} />
该路由点击时,只会匹配到home
<Link to='/home'>Message</Link>
<Route path='/home' component={Home} />
<Route path='/home/message' component={Message} />
该路由点击时,会匹配到home和home/message
严格匹配
<Link to='/home/message'>Message</Link>
<Route path='/home' exact component={Home} />
<Route path='/home/message' component={Message} />
添加exact: 严格匹配,路径必须完全匹配。未开启严格匹配时, to='/home/message'匹配到的是home
注意:exact有两种写法
exact exact='true'
Switch
相当于全部的严格模式
<switch>
写在这里的路由会遵循严格模式
</switch>
Redirect
Redirect 重定向,在路由没有匹配项时,会指向redirect
例:
<Link to='/home1/message1'>Message</Link>
<Route path='/home' component={Home} />
<Route path='/home/message' component={Message} />
<Route path='/about' component={About} />
<Redirect to="/about"/>
该路由中,点击时没有可以匹配的地址,所以会匹配到about
解决路由中样式丢失问题的3个方案
<link rel="stylesheet" href="./css/bootstrap.css">
1、把导入样式的路由修改为%PUBLIC_URL%/开头,代表public绝对路径下的文件
2、删除路径开头的’.’,不使用相对路径。即:/css/bootstrap.css样式
3、使用’#‘代替’.'解决哈希模式下的问题
一般组件和路由组件之间的区别
一般组件:程序员自己写组件标签渲染的,例如<Demo a="1" b="2"/>
路由组件:靠路由给我们渲染的,例如:<Route path="/demo" component={Demo}>
区别:路由组件的props上比一般组件多了3个属性,分别是:
history:路径和跳转相关的
location:history.location
match:传递参数相关
二级路由
注意:react和vue不同,react中路由的子路由必须把路径写全
路由传参
使用es6模板字符串方法填写路径
<Link to={
/home/message/detail/${msgObj.id}} >{msgObj.name}</Link>
在Route标签中接收
<Route path='/home/message/detail/:id' component={Detail} />
在Detail文件中使用props调用
const { id } = this.props.match.params
push和replace
1、可以直接在link标签中写replace={true}或push{true}来使该标签的请求为对应的方式
<Link to={`/home/message/detail/${msgObj.id}`} push={true} >{msgObj.name}</Link>
<Link to={`/home/message/detail/${msgObj.id}`} replace={true} >{msgObj.name}</Link>
2、借用this.props.history中的方法,定义push,repalce等方法
定义的方法可以直接在各种标签中使用
export default class HomeMessage extends Component {
没有刷新页面,但是有push的历史记录。可以回退
push = (id)=>{
this.props.history.push(`/home/message/detail/${id}`)
}
没有刷新页面,没有repalce的历史记录。回退的是repalce请求之前所请求的历史记录
repalce = (id)=>{
this.props.history.replace(`/home/message/detail/${id}`)
}
前进
forward = ()=>{
this.props.history.goForward()
}
后退
back = ()=>{
this.props.history.goBack()
}
render() {
return (
<div>
<button onClick={()=>{this.push(msgObj.id)}}>push查看</button>
<button onClick={()=>{this.repalce(msgObj.id)}}>replace查看</button>
<button onClick={this.back}>后退</button>
<button onClick={this.forward}>前进</button>
<hr/>
<Route path="/home/message/detail/:id" component={MessageDetail}/>
</div>
)
}
}
简写Link和NavLink
import React, { Component } from 'react'
import { NavLink } from "react-router-dom";
<!-- export default class index extends Component {
render() {
console.log(this.props);
return (
// <NavLink className="list-group-item" />
<NavLink activeClassName="demo" className="list-group-item" to={this.props.to}>{this.props.children} </NavLink>
// 简写为:
// <NavLink activeClassName="demo" className="list-group-item" {...this.props}/>
)
}
} -->
<!-- 可以更加简写为: -->
export default props =><NavLink activeClassName="demo" className="list-group-item" {...props}/>
在要使用的组件中引入MyNavLink组件代替NavLink即可
import MyNavLink from "./components/MyNavLink";
Link组件和NavLink相同,只是没有activeClassName="demo"这个属性