React项目实战步骤(后台系统)

一、项目起步

1.创建项目

$ npx create-react-app my_react

2、安装依赖

本项目用到的依赖可以预先安装好:

  • antd
  • redux与react-redux
  • react-router-dom
  • axios
$ npm i antd redux react-redux react-router-dom@6 axios --save

3.配置路由 (根据项目分析需要几个页面,以及页面之间的关系)

/* 
    App > List + Edit + Means
    Login
    Register
    History模式  --  BrowserRouter
    Hash模式     --  HashRouter
*/

import App from '../App'
import Edit from '../pages/Edit'
import List from '../pages/List'
import Means from '../pages/Means'
import Login from '../pages/Login'
import Register from '../pages/Register'
import {BrowserRouter as Router, Routes, Route} from 'react-router-dom'

const BaseRouter = () => (
    <Router>
        <Routes>
            <Route path='/' element={<App />}>
                <Route path='/edit' element={<Edit />}></Route>
                <Route path='/list' element={<List />}></Route>
                <Route path='/means' element={<Means />}></Route>
            </Route>
            <Route path='/login' element={<Login />}></Route>
            <Route path='/register' element={<Register />}></Route>
        </Routes>
    </Router>
)

export default BaseRouter

或者也可以写成这样(与·vue写法相似)

import App from '../App'
import Edit from '../pages/Edit'
import List from '../pages/List'
import Means from '../pages/Means'
import Login from '../pages/Login'
import Register from '../pages/Register'
import {Navigate} from 'react-router-dom'

export default  [
  
            { path:'/',
              element:<App />,
              children[
                {
                     path:'edit',
                     element:<Edit />
                },
                { 
                     path:'list',
                     element:<List/>
                },
                { 
                     path:'means',
                     element:<Means />
                }
               ]
            },

             { 
               path:'/login',
               element:<Login />
             },
             { 
               path:'/register',
               element:<Register />
             }
           ]

4.确认使用框架,编写静态代码

UI框架使用:Ant Design

在入口文件index.js中:

import ReactDOM from 'react-dom'
import App from './App'
import 'antd/dist/antd.css';

ReactDOM.render(
    <App />,
    document.getElementById('root')
)

然后在App.jsx中:

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

export default function App() {
  return (
    <div>
        <Button type="primary">Primary Button</Button>
    </div>
  )
}

如果可以看到这款颜色的按钮,即代表使用成功:

二、Request封装

1.在src下创建request目录,并在其中创建request.js及api.js

2.封装axios请求

(导入axios,定义并创建域名接口,然后共享全局变量)

request.js:

import axios from 'axios'

// 配置项
const axiosOption = {
    baseURL:  '域名' ,// 请求接口的域名
    timeout: 5000
}

// 创建一个单例
const instance = axios.create(axiosOption);

// 添加请求拦截器
instance.interceptors.request.use(function (config) {
  let token = localStorage.getItem('cms-token')
  if(token){
    config.headers = {
        'cms-token':window.localStorage.getItem('cms-token')
    }
  }
  return config;
}, function (error) {
  // 对请求错误做些什么
  return Promise.reject(error);
});

// 添加响应拦截器
instance.interceptors.response.use(function (response) {
  // 对响应数据做点什么
  return response.data;
}, function (error) {
  // 对响应错误做点什么
  return Promise.reject(error);
});

export default instance;

3.api.js

指API接口,在此之前需要导入request文件在获取时候可以传入接口参数,get方法获取则定义为params方法,post方法则定义data方法

import request from './request'
 
export const getNewsAPI = function (接口参数) {
  return request.get('接口的api', { params: { 接口参数 } })  // 多个参数用逗号隔开
}

4.在组件使用 

methods: {
    async initArticleList () {
      const { data: res } = await getNewsAPI(与组件对接的参数)  // 在此可以在组件中定义好参数方便存储
      console.log(res.data)
}

4.解决跨域

在  react 17.x中 

方法一:我们可以在package.json 中写

"proxy":{"这里写你要请求的地址"}

方案二(推荐):

先安装 http-proxy-middleware :

npm install http-proxy-middleware
或者
yarn add http-proxy-middleware

这里注意,http-proxy-middleware 模块是有版本区别的,默认安装最新版本,然后在 src 目录下新建 setupProxy.js :

 
const proxy = require('http-proxy-middleware');
// 这个玩意不用下,react里自己带了
 
module.exports = function(app) {
    app.use(
        proxy('/api1', {  // 发送请求的时候 react会自动去找这个api1,匹配这个路径,然后去发送对的请求
            target: 'http://localhost:5000',
            changeOrigin: true, //控制服务器接收到的请求头中host字段的值
            pathRewrite: {'^/api1': ''} // 跟上面匹配,这个api1只是找这个路径用的,实际接口中没有api1,所以找个目标地址后,要把api1给替换成空
        }),
        // changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
        // changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
        // 注意!!注意!!注意!! changeOrigin默认值为false,需要我们自己动手把changeOrigin值设为true
        proxy('/api2', {
            target: 'http://localhost:5001',
            changeOrigin: true,
            pathRewrite: {'^/api2': ''}
        }),
    )
}
 

在react18中

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:5001',
            changeOrigin: true,
            pathRewrite: { '^/api2': '' }
        }),
    )
}

或者,还有另一种方法

如果你已经进行了 npm run eject(会复制所有依赖文件和相应的依赖(webpack、babel等)到你的项目。是个单向的操作,一旦 eject ,npm run eject的操作是不可逆的) ,建议你直接修改 config>webpackDevServer.config.js :

proxy: {
  '/api': {
    target: 'http://47.93.114.103:6688/manage', // 后台服务地址以及端口号
    changeOrigin: true, //是否跨域
    pathRewrite: { '^/api': '/' }
  }
}

然后修改request.js:

const axiosOption = {
    baseURL: '/api',
    timeout: 5000
}

最后重新执行 npm run start

三.登陆页面重要逻辑部分(注册也一样)

Login.jsx:

import { Link, useNavigate} from 'react-router-dom'
//引入接口
import {LoginApi} from '../axios/api'

export default function Login() {

  const navigate = useNavigate()

  const onFinish = (values) => {
    // console.log('Success:', values);
    //使用APi请求数据
    LoginApi({
      username:values.username,
      password:values.password
    }).then(res=>{
      console.log(res);
      if(res.errCode===0){
        message.success('登陆成功');
        //存储数据(这里需要根据后端返回值来写)
        localStorage.setItem('avatar',res.data.avatar)
        localStorage.setItem('cms-token',res.data['cms-token'])
        localStorage.setItem('editable',res.data.editable)
        localStorage.setItem('player',res.data.player)
        localStorage.setItem('username',res.data.username)
        //跳转路径
        navigate('/')
      }else{
        message.error('用户已存在');
      }
    })
  };

四、路由跳转

使用useNavigate这个路由hook,可以实现路由跳转。若要判断这个路径如果为/,则自动跳转到/home,代码如下:

import React, {useEffect} from 'react'
import {Outlet, Link, useLocation, useNavigate} from 'react-router-dom'

function App() {
    let {pathname} = useLocation()
    const navigate = useNavigate()

    useEffect(()=>{
        if(pathname==='/'){
            navigate('/home')
        }
    }, [])

    return ...
}

export default App

五、useLocation

使用useLocation这个路由hook,可以获取地址栏路径:

import {useLocation} from 'react-router-dom'

function App() {
    let {pathname} = useLocation()		// 得到当前路径
}

六、参数携带

1、url子路由形式

通过在路由中配置子路由形式,可以实现参数传递。如给/list携带参数,以这个形式:/list/123。

// 路由文件
<Route path='/list/:id' element={<List />}></Route>

// App.jsx中
<li><Link to="/list/123">列表页</Link></li>

如果想要获取参数的值,可以使用useParams这个路由hook:

import React from 'react'
import {useParams} from 'react-router-dom'

export default function List() {
  const params = useParams()
  console.log(params)   // {id: '123'}
  return <h2>List列表页</h2>
}

2、问号?形式

地址栏携带参数还可以通过问号形式:

<li><Link to="/detail?id=456">详情页</Link></li>

获取该参数的方式,需要使用useSearchParams这个路由hook,并且调用getAll方法才能获取得到:

import React from 'react'
import {useSearchParams} from 'react-router-dom'

export default function Detail() {
  const [params] = useSearchParams()
  console.log(params.getAll('id'))  // ['456']
  return <h2>Detail详情页</h2>
}

3、state携带

以上两种携带参数的方式,都只能携带简单的参数,如果数据量较大,其实并不方便,因此,在使用useNavigate()这个hook实现跳转时,其实也可以携带参数:

navigate('/home', {
  state: {id: 789}
})

获取该参数的方式便是使用useLocation这个路由hook:

七、分页步骤

1.antd组件table内置了分页效果

return (
        <div className='list_table'>
            <Table
                showHeader={false}
                columns={columns}
                dataSource={arr}
                onChange={pageChange} //分页函数
                //分页效果,pagination值是动态可操作的,所以用useState来管理
                pagination={pagination} 
            />
        </div>
    )
const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0 })
//current、pageSize、total这三项是需要做配置的

配置完成以后,当点击下一页的时候,就可以得到那三个参数最新的值

const pageChange = (arg) => getArticleList(arg.current, arg.pageSize);

然后再一次的做请求,通过setPagination修改 useState里面的值

   // 提取请求的代码
    const getArticleList = (current, pageSize) => {
        ArticleListApi({
            num: current,
            count: pageSize
        }).then(res => {
            if (res.errCode === 0) {
                // 更改pagination
                let { num, count, total } = res.data;
                setPagination({ current: num, pageSize: count, total })
                // 深拷贝获取到的数组
                let newArr = JSON.parse(JSON.stringify(res.data.arr));
                // 声明一个空数组
                let myarr = []
                /* 
                    1. 要给每个数组项加key,让key=id
                    2. 需要有一套标签结构,赋予一个属性
                */
                newArr.map(item => {
                    let obj = {
                        key: item.id,
                        date: moment(item.date).format("YYYY-MM-DD hh:mm:ss"),
                        mytitle: <MyTitle id={item.id} title={item.title} subTitle={item.subTitle} />
                    }
                    myarr.push(obj)
                })
                setArr(myarr)
            }
        })
    }

 上面这一行就是再次请求

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值