likes
comments
collection
share

React全家桶项目实战(一)

作者站长头像
站长
· 阅读数 41

React全家桶项目开发

一、全家桶技术

React+函数组件+hooks+ReactRouter+ant design+ redux+echarts+其他技术栈

项目搭建

npx create-react-app react-mall

需要自己改造项目

二、antd组件库的搭建

在React开发过程中,使用ant design这个UI组件库来完成开发。

这个UI组件库蚂蚁金服开源的uI组件库,目前国内针对React项目用的最多的一个库

React版本地址为:ant-design.antgroup.com/docs/react/…

antd也提供vue的版本。你可以在Vue2或者Vue3中使用antd

Vue版本地址为:www.antdv.com/docs/vue/in…

(1)安装antd

yarn add antd
npm i antd

目前本文档截至使用的版本5.9.0

(2)组件中使用antd

import React from 'react'
import {Buttonfrom "antd"

export default function AntdComp() {
 return (
   <div>
       <h3>AntdComp</h3>
       <Button type='default'>按钮</Button>
       <Button type='dashed'>按钮</Button>
   </div>
)
}

以后在项目中,需要什么组件就自己引入这个组件就可以了。

antd5的版本默认已经实现了按需打包。引入过后用过组件才会打包,

antd的样式无需引入,antd4需要手动引入样式。打包的时候,默认就针对你用到组件打包样式

目前antd5中,大部分的组件都基于函数组件来开发的。

三、配置项目启动环境

启动项目的命令

"scripts": {
   "start": "react-scripts start",
   "build": "react-scripts build",
   "test": "react-scripts test",
   "eject": "react-scripts eject"
},

react-scripts:实际上是一个启动插件,启动项目,默认加载package.json里面配置文件。默认情况下,如果你启动项目。打包项目的时候,你需要给项目配置webpack内容。必须在package.json中

替换项目启动

craco插件第三方的插件,使用这个插件来替代react-scripts来启动项目。

(1)下载craco

你可以自己配置启动的webpack,或者一些环境变量等等

yarn add @craco/craco

下载完成后,我们需要在启动环境中替换为craco

(2)找到package.json
"scripts": {
   "start": "craco start",
   "build": "craco build",
   "test": "craco test",
   "eject": "craco eject"
},
(3)在项目根目录下面创建文件

在项目根目录下面创建文件craco.config.js

这个文件名字不能写错。默认采用craco来加载项目,读取这个文件。

可以在这个文件中配置webpack相关的内容

module.exports = {

}
(4)配置less环境

antd底层默认采用less来设计的代码

我们自己引入样式也有less来设计

yarn add craco-less

下载完成后,想要让craco启动项目能加载less环境。

打开craco.config.js文件。配置less的加载规则

const CracoLessPlugin = require("craco-less")
module.exports = {
   plugins: [
      { plugin: CracoLessPlugin }
  ]
}
(5)组件中引入less

在assets/styles/antdcomp.module.less文件中

.container{
   width:100px,
       height:100px,
           span{
               color:red
          }
}

引入到组件中

import React from 'react'
import {Buttonfrom "antd"
import style from "../assets/styles/antdcomp.module.less"

export default function AntdComp() {
 return (
   <div>
       <h3>AntdComp</h3>
       <Button type='default'>按钮</Button>
       <Button type='dashed'>按钮</Button>
       <div className={style.container}>
           <span>woniu</span>
       </div>
   </div>
)
}

四、主题色设计

antd使用组件库每个组件都默认设置了蓝色的主题。

如果需要修改主题色,参考antd官方给的配置。

全局配置,也可以局部配置

主题配置文档:ant-design.antgroup.com/docs/react/…

在antd4.x版本中,如果要配置主题色,我们在配置文件中全局配置。无法支持局部配置

(1)全局配置

控制所有组件主题色。需要在App.jsx这个根组件中,配置主题色

import AntdComp from "./components/AntdComp";
import Header from "./components/Header";
import { ButtonConfigProviderSpace } from 'antd';
function App() {
 return (
   <ConfigProvider
     theme={{
       token: {
         // Seed Token影响范围大
         colorPrimary: '#7cb305'
      },
    }}
   >
     <Space>
       <Button type="primary">Primary</Button>
       <Button>Default</Button>
     </Space>
     <AntdComp></AntdComp>
     <Header></Header>
   </ConfigProvider>
);
}

export default App;

ConfigProvider:这个组件antd5提供一个配置项组件,theme的属性可以设置新的主题颜色,覆盖默认的antd主题色。

(2)局部修改

可以针对某一个组件,组件中某一个局部区域进行主题色修改

需要在布局代码中使用ConfigProvider

Header.jsx子组件中,配置主题色

import React from 'react'
import { ButtonConfigProvider } from "antd"

export default function Header() {
   return (
       <div>
           <ConfigProvider theme={{
               token: {
                   // Seed Token影响范围大
                   colorPrimary: '#d4380d'
              },
          }}>
               <h3>Header</h3>
               <Button>修改</Button>
           </ConfigProvider>

       </div>
  )
}

五、函数组件开发

(1)基本概念

类组件开发特点:

  1. 基于面向对象开发模式,需要一定面向对象基础。
  2. 类组件包含了完整组件内部状态、外部状态、生命周期函数。
  3. 类组件相对来说复杂一点,包含this指向问题。尤其是事件绑定。

函数组件开发特点:

  1. 采用函数式编程,开发难度更低。符合JavaScript开发模式
  2. 函数组件默认没有组件内部状态,我们需要引入hooks解决组件内部状态
  3. 函数组件中没有生命周期函数,我们也需要引入hooks来解决生命周期函数问题
  4. 函数组件中,无需再使用this。开发难度会更低

hooks:实际上封装好的一系列函数,我们可以再函数组件中引入这些hook函数。辅助我们开发。

函数组件基础结构

import React from 'react'

const Login = () => {
   return (
       <div>Login</div>
  )
}
export default Login

用箭头函数来设计,并返回当前这个函数。页面加载你这个函数返回JSX模板。

说明:暴露出去的函数。外部直接调用。并不会实例化这个函数

目前公司中React项目开发,80%的项目都会采用函数组件来设计。采用类组件配合函数组件一起使用

(2)函数组件通信

跟类组件不一样的地方,在于子组件接受外部参数的时候。通过函数组件参数来接受props

import React from 'react'
import {Buttonfrom "antd"

//props = {msg,getMsgValue}
const Login = ({msg,getMsgValue}) => {
   return (
       <div>
           <h3>Login</h3>
           <p>{msg}</p>
           <Button onClick={()=>getMsgValue("xiniu")}>修改msg</Button>
       </div>
  )
}
export default Login

Login函数后面的参数,默认接受props对象。你可以解构出来。

在函数组件中定义函数,推荐用箭头函数

import React from 'react'
import { Button } from "antd"

const Login = ({ msg, getMsgValue }) => {
   //函数定义,采用箭头函数来设计
   const checkButton = () => {
       getMsgValue("woniuxueyuan")
  }
   return (
       <div>
           <h3>Login</h3>
           <p>{msg}</p>
           <Button onClick={ checkButton }>修改msg</Button>
       </div>
  )
}
export default Login

(3)useState函数

React官方为了解决函数组件没有内部状态。提供了一系列函数来辅助我们开发。

我们将这些函数称为hooks函数。

其中第一个要学习的函数useState,用于定义组件内部状态

import React,{useState} from 'react'
import { Button } from "antd"

const Login = ({ msg, getMsgValue }) => {
   const [username,setUsername] = useState("小王")
   const [count,setCount] = useState(100)
   const [student,setStudent] = useState({id:1,name:"小张",classes:{name:"三年二班"}})
   
   const checkButton = () => {
       setUsername("xiaofei")
  }
   const updateStudent = ()=>{
       const student2 = {...student}
       student2.name = "xiaofeifei"
       setStudent(student2)
  }

   return (
       <div>
           <h3>Login</h3>
           <p>{msg}</p>
           <p>{username}</p>
           <Button onClick={ checkButton }>修改msg</Button>
           <p>{count}</p>
           <Button onClick={ ()=>setCount(0) }>-</Button>
           <Button onClick={ ()=>setCount(200) }>+</Button>
           <p>{student.name}</p>
           <p>{student.classes.name}</p>
           <Button onClick={ updateStudent }>修改student</Button>
       </div>
  )
}
export default Login

useState来定义组件内部状态特点:

  1. 每个数据都分别采用useState来进行管理。所有数据分类处理
  2. 每个变量定义好了,都会有一个唯一的修改函数,对应修改过程
  3. 如果遇到引用类型数据,修改的时候检测修改对象地址是否新的。否则无法更新
  4. 修改函数,函数名字是可以用户自定义的。比如changecount,但是官方要求我们最好按照set+驼峰命名的方式来设计。可读性和维护性更高
  5. 修改函数,也是异步更新的,无法马上拿到修改过后结果。如果你要修改后,拿到结果。目前还无法解决

(4)useMemo函数

useMemo是React官方提供出的计算属性函数。可以用于页面数据进行数据处理

语法一:

const filterDate = useMemo(()=>{
   return 计算结果
},[监控属性])
const filterDate = useMemo(()=>{
   return 计算结果
},[监控属性1,监控属性2])

指定监控页面上某个属性,当这个值发生允许计算属性。

语法二:

const filterDate = useMemo(()=>{
   return 计算结果
})

监控页面上所有的数据,只有数据变化,计算属性都要执行一次。

这种写法比较消耗性能。页面很多数据可能都更新。

(5)useCallback函数

这个函数也是计算属性。

语法和useMemo一样。

但是返回值不是结果,而是一个函数,使用的需要调用一下

const filterData = useCallback(() => {
   switch (status) {
       case "all"return tasks;
       case "done"return tasks.filter(item => item.state);
       case "undone"return tasks.filter(item => !item.state)
  }
}, [status])

useCallback用于父子组件通信,解决页面更新问题。

(6)useRef函数

在函数组件中,提供了一个useRef的函数。这个函数可以获取页面中ref指向的节点。

用这种方式更加合理一些。

老方法:

<input type="text" ref={element=>Register.inputElement = element} />

ref接受一个函数,接受到结果需要用组件名字挂载。

新方法

import {useRef} from "react"


const inputRef = useRef()

//获取文本框值
const getValue = ()=>{
  const value =  inputRef.current.value
}

<input ref={inputRef}>

目前推荐大家使用useRef来获取节点,并得到结果

(7)useEffect副作用

在函数组件中,并没有生命周期函数。

所以React官方提出了useEfffect的函数,副作用。可以模拟生命周期函数

基于目前useEffect的特性,模拟componentDidMount

import React, { useEffect, useState } from 'react'

export default function ForgetPassword() {
   // 模拟componentDidMount
   const [count,setCount] = useState(0)
   useEffect(() => {
       console.log("componentDidMount");
  }, [])
   return (
       <div>
           <h3>ForgetPassword</h3>
           <p>{count}</p>
           <button onClick={()=>setCount(10)}>修改</button>
       </div>
  )
}

模拟componentDidUpdate

/**
    * setCount修改count的值,如何获取修改结果
    * 类似于Vue watch
    */
useEffect(()=>{
   console.log("componentDidUpdate");
   console.log(count);
},[count])

语法二:

useEffect(() => {
   console.log("componentDidUpdate");
})

表示页面上只要数据发生变化,都要执行一次这个函数。包括props

模拟componentWillUnmount

import React, { useEffect } from 'react'

export default function Children() {
   useEffect(()=>{
       //清除函数
       console.log("componentDidMount");
       return ()=>{
           console.log("componentWillUnmount");
      }
  },[])

   return (
       <div>Children</div>
  )
}

销毁函数和挂载函数,同一个语法。只是销毁的时候。多添加一个回调函数。

当React调用清除函数的时候,代表组件要销毁了

六、搭建路由

(1)概念讲解

React官网给他定义是一个库,并不是一个框架。

React官方并没有提供路由库,路由插件。

推荐我们使用React结合ReactRouter来进行路由的映射。

文档:reactrouter.com/en/main/sta…

框架路由开发模式,主要由一下几种:

  1. 编程式路由:需要自己在页面中写代码进行路由编程,包括映射。包括路由引入
  2. 配置式路由:只需要将路由映射写到配置文件中,剩下的就是自动渲染 Vuejs
  3. 约定式路由:无需配置路由,你的项目文件系统就是路由。Login.jsx\Register.jsx Login

Vuejs配置式路由

src/router/index.js

import VueRouter from "vue-router"
import Login from "./Login.vue"

const routes = [
  {
       path:"/login",
       name:"Login"
       component:Login
  }
]
const router = new VueRouter({
   routes,
   mode:"hash"
})

export default router

默认情况下,React项目中使用编程式路由。哪里用到,就在哪里配置

(2)搭建路由

下载对应路由包

yarn add react-router-dom
npm i react-router-dom

路由想要在App.jsx 组件搭建。

打开App.jsx配置路由

import AntdComp from "./components/AntdComp";
import Header from "./components/Header";
import Login from "./views/Login";
import Register from "./views/Register";
import ForgetPassword from "./views/ForgetPassword";
import { ButtonConfigProviderSpace } from 'antd';
import { BrowserRouterRoutesRoute } from "react-router-dom"
function App() {
 return (
   <ConfigProvider
     theme={{
       token: {
         // Seed Token影响范围大
         colorPrimary: '#7cb305'
      },
    }}
   >
    {/* 路由器 */}
     <BrowserRouter>
      {/* 路由映射列表 */}
       <Routes>
        {/* 路由具体路径匹配 */}
         <Route path="/login" element={<Login></Login>}></Route>
         <Route path="/register" element={<Register></Register>}></Route>
         <Route path="/forget" element={<ForgetPassword></ForgetPassword>}></Route>
       </Routes>
     </BrowserRouter>
   </ConfigProvider>
);
}

export default App;

(3)路由配置详解

路由器:BrowserRouter、HashRouter

路由器目前有两种,决定了当前路由的模式。

BrowserRouter:默认采用history模式

HashRouter:采用hash模式。路径访问的时候需要/#/

路由映射:Routes、Route主要负责进行路由路径匹配,提供渲染的组件

Routes:表示可以包含多个映射规则。从上到小的进行匹配。当匹配成功结束匹配

Route:进行路由映射,path路由路径,element提供映射组件。指定的这个地方渲染组件

路由导航:Link、NavLink

通过Link和NavLink组件可以实现路由的切换,类似于Vue router-link

(4)路由映射规则

默认索引和重定向

<Routes>
<Route index element={<Login></Login>}></Route>
</Routes>

默认进来匹配的组件就是Login组件。默认索引。index只能用一次

重定向规则

import {Navigatefrom "react-router-dom"

<Routes>
<Route path="/" element={<Navigate to="/login"></Navigate>}></Route>
</Routes>

我们还可以用重定向解决404的问题

完整页面

import AntdComp from "./components/AntdComp";
import Header from "./components/Header";
import Login from "./views/Login";
import Register from "./views/Register";
import ForgetPassword from "./views/ForgetPassword";
import { ButtonConfigProviderSpace } from 'antd';
import NotFind from "./views/NotFind";
import { BrowserRouter,HashRouterRoutesRoute,Link,NavLink,Navigate } from "react-router-dom"
function App() {
 return (
   <ConfigProvider
     theme={{
       token: {
         // Seed Token影响范围大
         colorPrimary: '#7cb305'
      },
    }}
   >
    {/* 路由器 */}
     <BrowserRouter>
      {/* 路由映射列表 */}
       <ul>
         <li>
           <Link to="/register">注册</Link>
         </li>
         <li>
           <NavLink to="/forget">忘记密码</NavLink>
         </li>
       </ul>
       <Routes>
        {/* 路由具体路径匹配 */}
         <Route path="/" element={<Navigate to="/login"></Navigate>}></Route>
         <Route path="/login" element={<Login></Login>}></Route>
         <Route path="/register" element={<Register></Register>}></Route>
         <Route path="/forget" element={<ForgetPassword></ForgetPassword>}></Route>
         <Route path="/404" element={<NotFind></NotFind>}></Route>
         <Route path="*" element={<Navigate to="/404"></Navigate>}></Route>
       </Routes>
     </BrowserRouter>
   </ConfigProvider>
);
}

export default App;

(5)嵌套路由

在Home路由下面嵌入Route路由实现嵌套

import AntdComp from "./components/AntdComp";
import Header from "./components/Header";
import Login from "./views/Login";
import Register from "./views/Register";
import ForgetPassword from "./views/ForgetPassword";
import { ButtonConfigProviderSpace } from 'antd';
import NotFind from "./views/NotFind";
import Home from "./views/Home";
import User from "./views/subs/User";
import Role from "./views/subs/Role";
import { BrowserRouterHashRouterRoutesRouteLinkNavLinkNavigate } from "react-router-dom"
function App() {
 return (
   <ConfigProvider
     theme={{
       token: {
         // Seed Token影响范围大
         colorPrimary: '#7cb305'
      },
    }}
   >
    {/* 路由器 */}
     <BrowserRouter>
      {/* 路由映射列表 */}
       <ul>
         <li>
           <Link to="/register">注册</Link>
         </li>
         <li>
           <NavLink to="/forget">忘记密码</NavLink>
         </li>
       </ul>
       <Routes>
        {/* 路由具体路径匹配 */}
         <Route path="/" element={<Navigate to="/login"></Navigate>}></Route>
         <Route path="/login" element={<Login></Login>}></Route>
         <Route path="/home" element={<Home></Home>}>
           <Route index element={<User></User>}></Route>
           <Route path="role" element={<Role></Role>}></Route>
         </Route>
         <Route path="/register" element={<Register></Register>}></Route>
         <Route path="/forget" element={<ForgetPassword></ForgetPassword>}></Route>
         <Route path="/404" element={<NotFind></NotFind>}></Route>
         <Route path="*" element={<Navigate to="/404"></Navigate>}></Route>
       </Routes>
     </BrowserRouter>
   </ConfigProvider>
);
}

export default App;

在Home下面配置路由渲染出口

import React from 'react'
import { OutletLink } from "react-router-dom"

export default function Home() {
   return (
       <div style={{ display: "flex" }}>
           <div style={{ width: "200px", backgroundColor: "pink" }}>
               <ul>
                   <li>
                       <Link to="/home/user">用户</Link>
                   </li>
                   <li>
                       <Link to="/home/role">角色</Link>
                   </li>
               </ul>
           </div>
           <div>
               <h3>content</h3>
               <Outlet></Outlet>
           </div>
       </div>
  )
}

Outlet组件就是路由渲染出口。

搭建好二级路由后,整体的布局效果如下:

React全家桶项目实战(一)

转载自:https://juejin.cn/post/7278300215060217897
评论
请登录