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>)
}