2024-10-18
官方推荐以框架开始,比如nextjs
。但是,为了学习,我这里介绍的是纯血react
开场。
简单来说,就是大家都用呗。
复杂来讲,为什么大家用呢?因为react对前端页面渲染相对于传统JS更高效。利用了虚拟DOM技术+diffing算法
,传统JS用的是真实DOM
技术。
真实DOM的缺点是:不能复用之前的数据,每一次都是刷新重新来。
虚拟DOM:复用了原来的DOM,只需要渲染改变的那个数据。
推荐yarn,因为经过测试,速度比较快:
yarn create react-app your-app-name
推荐npx来安装,比较快:
npx create-react-app your-app-name
如果失败了,可以换成国内源,但我测试下来,并没有帮助。老老实实用yarn
就好了。
最重要的是public
和src
文件夹。一个典型的react项目:
包含网站页签图标favicon、主页面index.html、所有css文件、图片等
包含App.jsx(也可以是.js或.ts或.tsx), App.css,index.css, index.js(入口文件),components等文件
跨域指不同源,比如3000端口访问5000端口的服务器。
在package.json文件添加以下代码:
"proxy": "http://localhost:5000"
修改前端代码改向3000端口请求:
axios.get('http://localhost:3000/students').then(
// 成功的回调
response => {console.log('成功了', response.data)},
// 失败的回调
error => {console.log('失败了', error)}
)
这个方法通过直接重定向3000请求到5000,解决跨域请求的问题。但是只能用一个服务器,如果有多个跨域服务器请求,就用以下setupProxy
的方式。
新建文件setupProxy.js
(注意:名称不能变)在src
文件夹下,添加以下代码:
const {createProxyMiddleware} = require("http-proxy-middleware");
module.exports = function(app){
app.use(
'/api1',
createProxyMiddleware({
target:'http://localhost:5000',
changeOrigin:true,
})
);
}
说明:所有访问3000/api1的都会重定向到5000端口上,因此避免了跨域问题。
这个办法是通过同源
策略来保证访问到服务器,可参考官方文档,跨域方法还可以在服务端设置CORS,可查看跨域和同源介绍。
状态提升
。比如下图中的数据state,是子组件components中Search
和List
共用的,就放到父组件App里面。
状态state在哪里,方法就在哪里。
通过props传递。
通过props传递,要求父提前给子传递一个函数。
兄弟给父传递,参照【子传父】,再由父传递给另一个兄弟,参照【父传子】。
任意两个组件的沟通,都可以借助PubSub工具。
yarn add pubsub-js
接收数据方订阅Subscribe
,发送数据方发布Publish
即可。
假设<List>组件是接收方,<Search>组件是发送方。
我们先看<List/>组件:
import PubSub from 'pubsub-js'
state = {// 初始化状态
users:[], //users初始值为数组
isFirst:true, //是否为第一次打开页面
isLoading:false, //标识是否处于加载中
err:'' //存储请求相关的错误信息
}
componentDidMount() {
// _表示不使用这个参数,这个参数是msg,现在只是占位。
this.token = PubSub.subscribe('communication', (_,stateObj)=>{
console.log('List组件收到数据了', stateObj);
this.setState(stateObj)
})
}
componentWillUnmount() {
PubSub.unsubscribe(this.token)
}
基本思路:
communication
,确定接收到的数据,比如stateObje
,setState改变状态。PubSub('name',data)
。再看<Search/>组件:
import PubSub from 'pubsub-js'
// 发送请求前通知List更新状态
PubSub.publish('communication', {isFirst:false, isLoading:true})
/* 发送api请求,比如axios */
// 发送请求前通知List更新状态
PubSub.publish('communication', {isFirst:false, isLoading:true})
// 发送网络请求
axios.get(`http://localhost:3000/api1/search/users?q=${KeyWord}`).then(
response => {
// 请求成功后通知List更新状态
PubSub.publish('communication', {isLoading:false, users:response.data.items})
},
error => {
console.log('失败了', error)
// 请求失败后通知List更新状态
PubSub.publish('communication', {isLoading:false, err:error.message})
}
)
格式是PubSub.publish('name', data)
。
思路:
明确导航区和展示区。
导航区的a标签改为Link标签;展示区Route标签进行路径的匹配。
最外层套一层BrowserRouter就行。
注意:
路由组件比如<About />要放在pages
文件夹,而不是components
文件夹
如果需要点击高亮,不用Link标签,用NavLink标签。
安装方法可以见react-router-dom官方文档,用yarn
安装:
yarn add react-router-dom
打开index.js
,包在最外层:
// 引入react-router-dom库
import { BrowserRouter } from 'react-router-dom';
// 渲染App组件到页面
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<React.StrictMode> {/* StrictMode检查React代码不合理的地方 */}
<App />
</React.StrictMode>
</BrowserRouter>
);
import { Link, Route, Routes } from 'react-router-dom'
{/* 在React中靠路由链接实现切换组件 */}
{/* 编写路由链接 */}
<Link className="list-group-item" to="/about">About</Link>
<Link className="list-group-item" to="/home">Home</Link>
{/* 注册路由 */}
<Routes>
<Route path="/about" element={<About />} />
<Route path="/home" element={<Home />} />
</Routes>
这样就可以实现多页面的切换了。
使用NavLink标签,示例代码:
import { NavLink, Route, Routes } from 'react-router-dom'
<NavLink className={({isActive}) => 'list-group-item' + (isActive ?' atguigu' : '')} to="/about">About</NavLink>
<NavLink className={({isActive}) => 'list-group-item' + (isActive ?' atguigu' : '')} to="/home">Home</NavLink>
两者都可以用。HashRouter的路径会带井号#。比如localhost:3000/#About
区别是井号#后面的值是哈希值,是不会作为资源发送给服务器的。一般用BrowserRouter就可以。
我们用serve
这个库就行。
全局安装:
npm i serve -g
生成build文件:
npm run build
在项目路径下使用serve命令:
serve build
这样,就能在本地3000或者5000端口来模拟服务器运行网站的效果了。