目录
一、创建项目并启动
第一步,全局安装:npm i -g create-react-app
第二步,切换到想创项目的目录,使用命令:create-react-app hello-react
第三步,进入项目文件夹:cd hello-react
第四步,启动项目:npm start
二、脚手架配置代理(项目只用配置一次)
1. 在package.json里面配置
"proxy": "http://localhost:5000"
2.在src文件下新建setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware')
module.exports = function (app) {
app.use(
createProxyMiddleware('/api1', {
target: "http://localhost:5000",
changeOrigin: true,
pathRewrite: { '^/api1': '' }
}),
createProxyMiddleware('/api2', {
target: "http://localhost:5000",
changeOrigin: true,
pathRewrite: { '^/api2': '' }
}),
)
}
三、父子间通信
1.父亲向儿子利用props传递一个函数
//父组件
export default class App extends Component {
state = { sum: 0 }
parent = (value) => {
this.setState({ sum: this.state.sum + value })
}
render () {
return (
<div>
<h1>我是父组件:{this.state.sum}</h1>
<Child parent={this.parent} />
</div>
)
}
}
2.子组件通过传递形参的方式给父组件传值
function Child (props) {
return (
<div>
<button onClick={() => { props.parent(1) }}>我是子组件,点击为父组件加一</button>
</div>
)
}
四、订阅与发布
需要安装第三方的库:npm install pubsub-js --save 注意订阅函数的第一个参数是空的_
1.import PubSub from 'pubsub-js' //引入
2.PubSub.subscribe('delete', function(data){ }); //订阅
PubSub.publish('delete', data) //发布消息
、、、、、、、使用、、、、、、、、
PubSub.unsubscribe(this.token) // 取消订阅 //参数为订阅的返回值的名字
this.token = PubSub.subscribe('atguigu', (msg, data) => {this.setState(data)}) //订阅 //第一个参数为名字、第二个参数为回调函数
PubSub.publish('atguigu', { isLoading: false, err: error.message }) //发布消息 第一个参数为名字、第二个参数为数据
import PubSub from 'pubsub-js'
import { useState } from 'react'
import { useEffect } from 'react'
export default class App extends Component {
render () {
return (
<div>
<h1>我是父组件</h1>
<ChildA />
<ChildB />
</div>
)
}
}
function ChildA () {
const [msgB, setMsgB] = useState((value) => {
return ""
})
useEffect(() => {
PubSub.subscribe("B", (_, data) => {
setMsgB(data)
})
}, [])
return (
<div>
<h4>我是子组件A,我要给子组件B发消息,我收到来自B组件的信息为:{msgB}</h4>
</div>
)
}
function ChildB () {
return (
<div>
<input type="text" placeholder='请输入发给子组件A的信息' onChange={(e) => { PubSub.publish("B", e.target.value) }} />
</div>
)
}
五、Fetch请求
1.文档地址:fetch documentation 传统 Ajax 已死,Fetch 永生 - SegmentFault 思否
2. 特点:fetch: 原生函数,不再使用XmlHttpRequest对象提交ajax请求,老版本浏览器不支持
1.get请求
fetch(url).then(function(response) {
return response.json()
}).then(function(data) {
console.log(data)
}).catch(function(e) {
console.log(e)
});
2.post请求
fetch(url, {
method: "POST",
body: JSON.stringify(data),
}).then(function(data) {
console.log(data)
}).catch(function(e) {
console.log(e)
})
六、路由
react-router-dom在2021年11月升级到了6版本
现在学的是5版本,执行:npm i react-router-dom@5
1.在React中靠路由链接实现切换组件:
BrowserRouer:这个路径没有#号 这个一般都写在index.js里面包裹APP组件就好了
HashRouter:这个有#号
<BrowserRouter>
<Link className="list-group-item" to="/about">About</Link>
<Link className="list-group-item" to="/home">Home</Link>
</BrowserRouter>
<BrowserRouter>
<App /> 包裹
</BrowserRouter>
{/* 在React中靠路由标签实现切换组件 放在index.js里面的省略*/}
<Link className="list-group-item" to="/about">About</Link>
<Link className="list-group-item" to="/home">Home</Link>
{/* 注册路由 */}
<Route path='/about' component={About} />
<Route path='/home' component={Home} />
2.路由组件与一般组件
路由组件一般是放在pages目录或者views目录下
3.NavLink (高亮效果路由)
activeClassName为地址是匹配后高亮效果
<NavLink activeClassName="atguigu" className="list-group-item" to="/about">About</NavLink>
<NavLink activeClassName="atguigu" className="list-group-item" to="/home">Home</NavLink>
4.NavLink的封装
(1)新建一个组件
export default class MyNavLink extends Component {
render() {
return (
<NavLink activeClassName="atguigu" className="list-group-item" {...this.props} />
)
}
}
(2)使用
<MyNavLink to="/about" a={123}>About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink> //Home拿的画就是他的一直children属性
5.Switch
单一匹配原则:提高匹配效率
<Switch>
<Route path='/atguigu/about' component={About} />
<Route path='/atguigu/home' component={Home} />
</Switch>
6、严格匹配与模糊匹配
一般情况不要随便开
{/* 注册路由 严格匹配 exact(默认为模糊匹配)*/}
<Switch>
<Route exact path='/atguigu/about' component={About} />
<Route exact path='/atguigu/home' component={Home} />
</Switch>
7、Redirect的使用
都没匹配上旧会执行Redirect的代码
{/* 注册路由 严格匹配 exact(默认为模糊匹配)*/}
<Switch>
<Route exact path='about' component={About} />
<Route exact path='home' component={Home} />
<Redirect to="/about" />
</Switch>
8、嵌套路由
在路由组件里面接着写路由
<ul className="nav nav-tabs">
<MyNavLink to="/home/news">News</MyNavLink>
<MyNavLink to="/home/message">Message</MyNavLink>
</ul>
{/* 注册路由 */}
<Switch>
<Route path="/home/news" component={News} />
<Route path="/home/message" component={Message} />
<Redirect to="/home/news" />
</Switch>
9.向路由组件传递params参数
接收参数:this.props.match.params
(1)传递
state = {
messageArr: [
{ id: "01", title: '消息1' },
{ id: "02", title: '消息2' },
{ id: "03", title: '消息3' },
]
}
<Link to={`/home/message/detail/${item.id}/${item.title}`}>{item.title}</Link>
<Route path="/home/message/detail/:id/:title" component={Detail} />
(2)接收显示 : this.props.match.params
const detailData = [
{ id: '01', content: "你好,中国" },
{ id: '02', content: "你好,尚硅谷" },
{ id: '03', content: "你好,未来的自己" },
]
export default class Detail extends Component {
render() {
const { id, title } = this.props.match.params
const findResult = detailData.find((detailObj) => {
return detailObj.id === id
})
return (
<div>
<li>ID:{id}</li>
<li>Title:{title}</li>
<li>Content:{findResult.content}</li>
</div>
)
}
}
10.向路由传递search参数
接收参数:this.props.location.search
(1)传递
state = {
messageArr: [
{ id: "01", title: '消息1' },
{ id: "02", title: '消息2' },
{ id: "03", title: '消息3' },
]
}
{/* 向路由组件传递search参数 */}
<Link to={`/home/message/detail/?id=${item.id}&title=${item.title}`}>{item.title}</Link>
(2)接收显示
// 接收search参数
const { search } = this.props.location
const { id, title } = qs.parse(search.slice(1))
<div>
<li>ID:{id}</li>
<li>Title:{title}</li>
<li>Content:{findResult.content}
</li>
</div>
11.向路由组件传递state参数
接收参数:this.props.location.state
(1)传递
{/* 向路由组件传递state参数 */}
<Link to={{ pathname: '/home/message/detail', state: { id: item.id, title: item.title } }}>{item.title}</Link>
(2)接收state参数并显示
const { id, title } = this.props.location.state || {}
12.push与replace
push:一个一个的往上加
replace:替换掉上一个,返回到前第二个
<Link replace={true} to={{ pathname: '/home/message/detail', state: { id: item.id, title: item.title } }}>{item.title}</Link>
13.编程式跳转
*replace跳转
(1)replace跳转+携带params参数
this.props.history.replace(`/home/message/detail/${id}/${title}`)
(2)replace跳转+携带search参数
this.props.history.replace(`/home/message/detail/?id=${id}&title=${title}`)
(3)replace跳转+携带state参数
this.props.history.replace(`/home/message/detail`, { id, title })
*push跳转
(1)push跳转+携带params参数
this.props.history.push(`/home/message/detail/${id}/${title}`)
(2)push跳转+携带search参数
this.props.history.push(`/home/message/detail/?id=${id}&title=${title}`)
(3)push跳转+携带state参数
this.props.history.push(`/home/message/detail`, { id, title })
14.withRouer的使用
//withRouter可以加工一般组件,让一般组件具备路由组件所特有的API
// withRouter的返回值是一个新组件
class Header extends Component {}
export default withRouter(Header)
15.BrowerRouter与HashRouter的区别
1.底层原理不同:
BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。HashRouter使用的是URL的哈希值。
2.url表现形式不同:
BrowserRouter的路径没有#,例如:localhost:30000/demo/test
HashRouter的路径包含#,例如:localhost:30000/#/demo/test
3.刷新后对路由参数的影响
BrowserRouter没有影响。因为state保存在histroy对象中
HashRouter刷新后会丢失
4.备注:HashRouter可以用于解决一些路径错误有的有关问题