React全家桶
一、脚手架配置代理(proxy)的方式
CORS:
请求url:http://www.baidu.com
发送url:http://www.jd.com
response.setHeader('Access-Control-Allow-Origin','*');
-
通过express快速搭建一个服务
-
创建一个图书组件
import React, { useEffect } from 'react'
import axios from 'axios'
export default function Books() {
//在组件挂载完成之后,相当于ComponentDidMount()方法,进行ajax请求
useEffect(() => {
//ajax请求
async function main() {
let result = await axios.get('http://127.0.0.1:5000/books');
console.log(result)
}
main();
}, [])
return (
<div>Books</div>
)
}
- 在package.json文件中添加一行配置
"proxy":"http://127.0.0.1:5000"
重启服务
这一步非常重要
- 修改请求的url地址
async function main() {
let result = await axios.get('/books');
console.log(result)
}
main();
- 但是这种方式相对单一,只能配置一个代理,如果想要配置多个代理,这就不行了
- 解决办法:需要在
src
的根目录中创建一个setupProxy.js
文件,注意文件名不能修改
- 安装一个包:npm i http-proxy-middleware
//1、导包
const proxy = require('http-proxy-middleware');
//2、导出一个方法
module.exports = function (app) {
app.use(
proxy.createProxyMiddleware('/api', {
//请求的目的地址
target: 'http://127.0.0.1:5000',
//控制服务器收到的请求头中Host的值
changeOrigin: true,
//重写路径
pathRewrite: {
'^/api': ''
}
})
)
}
- 修改代码
import React, { useEffect, useState } from 'react'
import axios from 'axios'
export default function Books() {
let [booklist, setBookList] = useState([]);
useEffect(() => {
//ajax请求
async function main() {
let result = await axios.get('/api/books');
if (result.status >= 200 && result.status < 300) {
setBookList(result.data)
}
}
main();
}, [])
return (
<div>
<h3>图书列表</h3>
<hr />
<ul>
{
booklist.map(item => {
return <li key={item.id}>{item.name}</li>
})
}
</ul>
</div>
)
}
- 再次基础之上添加模糊搜索功能
- Book.jsx
import React, { useState } from 'react'
import Header from './Header/Header'
import Main from './Main/Main'
import axios from 'axios'
export default function Books() {
let [booklist, setBookList] = useState([]);
let searchBookList = async (v) => {
let result = await axios.get('/api/books', {
params: {
name: v
}
});
setBookList(result.data)
}
return (
<div>
<h3>图书列表</h3>
<hr />
<Header searchBookList={searchBookList} />
<Main booklist={booklist} />
</div>
)
}
Header.jsx
import React, { useRef } from 'react'
export default function Header(props) {
let { searchBookList } = props;
let bookname = useRef();
let searchBook = () => {
//获取文本框中的数据
let book = bookname.current.value;
if (book === '') {
alert('请输入书名');
return;
}
searchBookList(book)
//清空文本框中的数据
bookname.current.value = ''
}
return (
<div>
请输入图书名称:<input type="text" ref={bookname} />
<button onClick={searchBook}>搜索</button>
</div>
)
}
Main.jsx
import React from 'react'
export default function Main(props) {
let { booklist } = props;
return (
<ul>
{
booklist.map(item => {
return <li key={item.id}>{item.name}</li>
})
}
</ul>
)
}
二、组件间的通信
react中的组件间的通信有三种:父子间、兄弟间、祖孙间
2.1 父子间组件通讯(props)
2.1.1 父->子
直接通过props属性向子组件传递数据,可以是一般的纯数据 <子组件 num={20}/>
也可以是父组件中的状态数据,当父组件中的状态数据更改,也会影响到子组件
2.1.2 子->父
默认情况下子是被动接收数据的一方,是没有办法直接修改父组件中的数据,但是如果父组件传递一个可以修改父
组件的状态数据的方法,通过props的形式给子组件,那么子组件修改的值是可以 影响父组件中的状态数据
2.2 祖孙间(任意后代)组件通讯(context)
2.2.1 祖-> 孙
- 调用 React. createContext() 创建 context 对象 【谁主动传递数据,就在谁的身上添加这个对象】
const context = React.createContext()
- 在
外部组件
中使用 context 上的 Provider 组件作为父节点, 使用value属性定义要传递的值
<context.Provider value={要传递的值}> 提供数据
<div className="App">
<Child1 />
</div>
</context.Provider>
- 孙组件中导入祖组件
import { context } from '../GrandFather/GrandFather'
- 孙组件接收祖组件传递的数据
- 方式1:利用Hook钩子函数中的useContext方法接收传递的数据
import React, { useContext } from 'react'
let name = useContext(context);
console.log(name);
- 方式2:利用context 上的 Consumer组件作为父节点,在其中使用{}添加回调函数写法
import React from 'react'
import { context } from '../GrandFather/GrandFather'
export default function Son() {
return (
<div style={{ width: 400, height: 200, border: '1px dashed green' }}>
<context.Consumer>
{
name => <p>姓名:{name}</p> #name可以自定义,表示提供者提供的value数据
}
</context.Consumer>
</div>
)
}
2.2.2 孙->祖
- 将祖组件中的数据做成状态数据,然后将初始状态数据以及修改状态数据通过value一并传递给孙组件
- 孙组件接收并进行修改
例如:将GrandFather组件中的数据传递给Son组件
GrandFather.jsx
import React, { createContext, useState } from 'react'
import Father from '../Father/Father'
export let context = createContext();
export default function GrandFather() {
// let name = '李四'
let [name, setName] = useState('李四');
let [age, setAge] = useState(20)
return (
<div style={{ width: 400, height: 400, border: '1px dashed #ccc' }}>
<h4>GrandFather组件</h4>
<p>姓名:{name}</p>
<p>年龄:{age}</p>
<hr />
<context.Provider value={[name, setName, age, setAge]}>
<Father />
</context.Provider>
</div>
)
}
Father.jsx
import React, { useContext } from 'react'
import Son from '../Son/Son'
import { context } from '../GrandFather/GrandFather'
export default function Father(props) {
// let { age, changeAge } = props;
let result = useContext(context);
console.log(result)
let updateAge = (num) => {
return () => {
// changeAge(20)
result[3](result[2] + num);
}
}
return (
<div style={{ width: 400, height: 300, border: '1px dashed red' }}>
<h4>Father组件</h4>
<span>年龄:{result[2]}</span>
<hr />
<button onClick={updateAge(100)}>更新年龄</button>
<hr />
<Son />
</div>
)
}
Son.jsx
// import React, { useContext } from 'react'
import { context } from '../GrandFather/GrandFather'
export default function Son() {
// let name = useContext(context);
let changeName = (f) => {
f('王五');
}
return (
<context.Consumer>
{
value => (
<div style={{ width: 400, height: 200, border: '1px dashed green' }}>
<h4>Son组件</h4>
<p>姓名:{value[0]}</p>
<button onClick={e => changeName(value[1])}>修改姓名</button>
</div >
)
}
</context.Consumer>
)
}
一般应用中不使用, 但一些插件库内部会使用context封装, 如: react-redux
2.3 兄弟间组件通讯(pub/sub)
【注意:兄弟间的组件是非嵌套式写法的组件
】
发布订阅机制: publish(发布者) / subscribe(接受者)
pubsub-js是一个用JS编写的库。
利用订阅发布模式, 当一个组件的状态发生了变化,可以通知其他任意组件更新这些变化
- 安装:
npm install pubsub-js
- 导入
import PubSub from "pubsub-js" // 导入的PubSub是一个对象.提供了发布/订阅的功能
- 在
发送消息的组件
调用
PubSub.publish('频道名称','值');
- 在
接收消息
的组件中调用
PubSub.subscribe('频道名称',(msg,data)=>{
//回调函数中的第一个参数:频道名称
//回调函数中的第二个参数:值
console.log(msg);
console.log(data);
});
- 取消订阅
PubSub.unsubscribe('频道名称');
A.jsx
import React from 'react'
import B from '../B/B'
import C from '../C/C'
export default function A() {
return (
<div>
<B />
<C />
</div>
)
}
B.jsx
import React from 'react'
import PubSub from 'pubsub-js'
export default function B() {
let sendData = () => {
PubSub.publish('keywords', '张三丰');
}
return (
<div style={{ width: 400, height: 100, border: '1px dashed #ccc' }}>
<h4>我是B组件</h4>
<button onClick={sendData}>向C组件发送数据</button>
</div>
)
}
C.jsx
import React, { useEffect, useState } from 'react'
import PubSub from 'pubsub-js'
export default function C() {
let [name, SetName] = useState('')
useEffect(() => {
PubSub.subscribe('keywords', (msg, data) => {
SetName(data);
});
return () => {
PubSub.unsubscribe('keywords');
}
}, [])
return (
<div style={{ width: 400, height: 150, border: '1px dashed red' }}>
<h3>我是C组件</h3>
<p>姓名:{name}</p>
</div>
)
}