React拓展开发

React 07. 拓展开发

一、课程大纲

1、复习axios react redux项目管理

2、计算属性:自定义函数、reselectrepure

3、调试工具:react-devtools

4、异步请求辅助函数:react-thunk

二、课程内容

1、项目讲解

(1) 项目初始化

创建项目

$ npx create-react-app app01

项目降级

$ npm i react@17 react-dom@17 -S

修改启动文件:src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';


ReactDOM.render(
  <App></App>,
  document.querySelector("#root")
)

安装项目依赖:

$ npm i react-router-dom@5 redux react-redux axios antd --force -S

(2) 初始化模块

① 封装异步请求模块src/plugins/http.js

/** 异步请求模块 */
import { Component } from 'react'
import axios from "axios";

const instance = axios.create({
  baseURL: 'http://localhost:9527'
})

instance.interceptors.request.use( request => {
  return request
})

instance.interceptors.response.use( response => {
  return response.data
})

Component.prototype.$http = instance

export default instance

主模块src/index.js中引入生效

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

import './plugins/http'   // 引入异步请求模块


ReactDOM.render(
  <App></App>,
  document.querySelector("#root")
)

② 封装路由模块

src/router/index.js:路由映射规则

/** 路由映射规则配置文件 */

const routes = [
  
]

export default routes

src/router/RouterView.jsx:路由组件

import React, {Suspense} from 'react'
// import { Spin } from 'antd';

import {  
  Route,
  Redirect,
  Switch
} from 'react-router-dom'

export default function RouterView(props) {
  
  const { routes } = props

  return (
    
      
        {
          routes.map(route => {
            if(route.redirect) {
              // 重定向
              return 
                        
                      
            } else {
              // 正常跳转
              return  {
                              return 
                            }}>
                      
            }
          })
        }
      
    
  )
}

ant design封装

建议参考官方文档,使用高级语法进行封装

安装依赖(核心库、图标库)

$ npm i antd @ant-design/icons --force -S

安装高级配置依赖

$ npm i @craco/craco craco-less --force -S

添加配置文件:app01/craco.config.js

const CracoLessPlugin = require('craco-less');

module.exports = {
  plugins: [
    {
      plugin: CracoLessPlugin,
      options: {
        lessLoaderOptions: {
          lessOptions: {
            modifyVars: { '@primary-color': '#1DA57A' },
            javascriptEnabled: true,
          },
        },
      },
    },
  ],
};

修改启动配置文件:package.json

...
"scripts": {
  "start": "craco start",
  "build": "craco build",
  "test": "craco test",
  "eject": "craco eject"
},
...

修改src/App.css 重命名src/App.less,在App.js中引入

import './App.less';

function App() {
  return (
    <div className="App">
      <h2>入口模块</h2>
    </div>
  );
}

export default App;

小总结:

项目初始化过程,主要包含了如下步骤:

1、创建项目,项目降级

2、安装axios封装异步请求模块

3、安装react-router-dom封装路由模块

4、安装ant design,通过craco方式,封装界面组件库

(3) 组件路由

后台管理系统,区分一级路由组件和嵌套路由组件

① 分析组件构成

src/
	views/
		Login/
		Reg/
		Main/
		
		Home/
		
		Menus/
		Roles/
		Users/
		
		Brand/
		Goods/
		About/

② 创建组件

③ 添加路由规则

/** 路由映射规则配置文件 */
import {lazy} from 'react'

// 项目展示的第一个页面,直接导入
import Login from '../views/Login'

const routes = [
  {
    name: 'r',
    path: '/',
    redirect: '/login',
    exact: true
  },
  {
    name: 'Login',
    path: '/login',
    component: Login,
    exact: false
  },
  {
    namt: 'Reg',
    path: '/reg',
    component: lazy( () => import('../views/Reg') ),
    exact: false
  },
  {
    name: 'Main',
    path: '/main',
    component: lazy( () => import('../views/Main')),
    exact: false,
    children: [
      {
        name: 'Home',
        path: '/main/home',
        component: lazy( () => import('../views/Home')),
        exact: false,
      },
      {
        name: 'Menus',
        path: '/main/menus',
        component: lazy( () => import('../views/Menus')),
        exact: false,
      },
      {
        name: 'Roles',
        path: '/main/roles',
        component: lazy( () => import('../views/Roles')),
        exact: false,
      },
      {
        name: 'Users',
        path: '/main/users',
        component: lazy( () => import('../views/Users')),
        exact: false,
      },
      {
        name: 'Brand',
        path: '/main/brand',
        component: lazy( () => import('../views/Brand')),
        exact: false,
      },
      {
        name: 'Goods',
        path: '/main/goods',
        component: lazy( () => import('../views/Goods')),
        exact: false,
      },
      {
        name: 'About',
        path: '/main/about',
        component: lazy( () => import('../views/About')),
        exact: false,
      }
    ]
  }
]

export default routes

src/App.js配置一级路由

import './App.less';

import {
  BrowserRouter as Router
} from 'react-router-dom'

import routes from './router';
import RouterView from './router/RouterView'

function App() {
  return (
    
); } export default App;

src/views/Main.js配置嵌套路由

import React, { Component } from 'react'

import { NavLink } from 'react-router-dom'
import { Space } from 'antd'

import RouterView from '../../router/RouterView'

export default class Main extends Component {
  render() {
    return (
      
首页 菜单管理 角色管理 用户管理 品牌管理 商品管理 关于我们
) } }

(4) 页面布局

① 登录页面

  • 和用户业务相关,登录页面需要还原UI设计稿
  • 和管理系统相关,开发简洁明了的登录视图即可
import React, { Component } from 'react'
import { Button, Form, Input, Card } from 'antd';
import { Link } from 'react-router-dom'
import './Login.less'

export default class Login extends Component {
  onFinish(values) {
    console.log('Success:', values);
  };

  onFinishFailed(errorInfo) {
    console.log('Failed:', errorInfo);
  };

  render() {
    return (
      
注册}>
) } }

② 注册页面

  • 和用户业务相关,登录页面需要还原UI设计稿
  • 和管理系统相关,开发简洁明了的登录视图即可
  • 参考登录页面的实现

③ 后台首页

(5) 异步数据管理

① 通过redux模拟管理数据

react组件生命周期,模拟虚拟数据,将虚拟数据通过actionCreators函数添加到状态管理中

  • 存在的问题:数据不应该是模拟的,应该从数据接口获取
componentDidMount() {
  // 初始化模拟数据
  const initData = [
    {id: 2, bname: "华为", bprice: 2999},
    {id: 1, bname: "中兴", bprice: 1999}
  ] 
  // 调用actionCreator初始化数据
  this.props.brandInitAction(initData)
}

axios异步请求数据

react组件生命周期中,发送异步请求,获取数据,并通过actionCreators函数初始化数据

  • 存在的问题:数据不应该由react组件管理,所有数据的CRUD实际操作应该由redux完成
componentDidMount() {
  // axios请求数据
  // 思考:这里发送异步请求,请求数据,完成数据初始化,合适吗?
  this.$http.get('/brand/list').then(response => {
    if(response.code === 200) {
      // 初始化异步数据
      this.props.brandInitAction(response.data)
    }
  })
}

③ 完善异步请求过程

项目中添加redux-thunk支持,让actionCreators中的action函数可以返回可执行的函数,我们就可以在actionCreators中添加异步请求操作

# 编辑 src/store/index.js,添加redux-thunk支持
/** 状态管理模式 */
import { 
  legacy_createStore as createStore, 
  combineReducers,
  applyMiddleware     // 1.中间件支持模块
} from 'redux'

import thunk from "redux-thunk"     //2. 异步支持模块

import brandReducer from './brand/brandReducer'

const store = createStore( combineReducers({
  brand: brandReducer
}), applyMiddleware(thunk) )   // 3.给store添加异步请求模块支持

export default store

# 编辑 src/store/brand/actionCreators.js, 添加异步请求初始化数据的操作
import {....} from './actionType'

import axios from '../../plugins/http'
....
// export const brandInitAction = data => ({type: brandInitType, data})
export const brandInitAction = () => {
  // redux-thunk 允许actionCreators返回一个函数(自动执行函数)
  return dispatch => {
    // 如果让redux actionCreators添加异步操作,需要中间件支持(redux-thunk)
    axios.get('/brand/list').then(response => {
      if(response.code === 200) {
        return dispatch({type: brandInitType, data: response.data})
      }
    })
  }
}

(6) 请求适配层

一般前后端分离项目中,后端接口的地址和url路径经常发生变化,如果我们将异步请求过程直接写在redux中的actionCreators的函数中,后期的维护工作量非常庞大!

所以前端项目中,我们会创建一个专门处理异步请求的独立模块,负责通过异步函数获取对应的数据,并且给前端应用提供固定的函数名称;如果后端接口后期出现需求变动,前端项目只需要维护请求模块即可!

创建的请求模块:src/request/brand.js

import axios from '../plugins/http'

// 导出一个查询品牌列表的异步函数
export const getBrandList = async () => await axios.get('/brand/list')
// ...

重构actionCreators处理函数,编辑src/store/brand/actionCreators.js

import {  
  brandAddType,
  brandEditType,
  brandDelType,
  brandInitType
} from './actionType'

// import axios from '../../plugins/http'
// 导入异步请求模块
import { getBrandList } from '../../request/brand'

export const brandAddAction = data => ({type: brandAddType, data})
export const brandEditAction = data => ({type: brandEditType, data})
export const brandDelAction = data => ({type: brandDelType, data})
// export const brandInitAction = data => ({type: brandInitType, data})
export const brandInitAction = () => {
  // redux-thunk 允许actionCreators返回一个函数(自动执行函数)
  return async dispatch => {
    // 使用封装的异步请求模块处理数据
    let result = await getBrandList()
    dispatch({type: brandInitType, data: result.data})
  }
}

2、项目调试

react项目,同样支持浏览器插件调试功能,通过图形化界面的方式观察数据以及数据的操作流程

  • 浏览器插件:react-devtools,安装在浏览器上
  • 调试模块:react-devtools-extension,需要添加到代码中

(1)redux-devtools

打开浏览器的管理插件面板,将插件添加到浏览器中,便于测试

React拓展开发_第1张图片

(2) redux-devtools-extension

项目调试模块,安装

$ npm i redux-devtools-extension -S

编辑数据模块:src/store/index.js,添加调试支持

/** 状态管理模式 */
import { 
  legacy_createStore as createStore, 
  combineReducers,
  applyMiddleware 
} from 'redux'

// 1.>>>>>>>>>>>>>>导入数据调试模块
import { composeWithDevTools} from "redux-devtools-extension"

import thunk from "redux-thunk" 

import brandReducer from './brand/brandReducer'

// 2.>>>>>>>>>>>>>>将数据调试模块,挂载到store实例上
const store = createStore( combineReducers({
  brand: brandReducer
}), composeWithDevTools(applyMiddleware(thunk)) )

export default store

重启浏览器,访问当前react项目:检查窗口中可以通过可视化界面监控项目中的数据

React拓展开发_第2张图片

3、数据运算

(1)reselect

Vuex中有一个getters模块,可以用于自动运算,类似计算属性的功能

react中第三方提供了一个用于缓存数据计算的模块:reselect

  • 注意事项:千万不要拼写错误,reselector X
$ npm i reselect -S

创建一个缓存结果的操作函数,不论在任何时候调用,如果参与运算的数据没有发生变化,直接返回上一次缓存的运算结果:(和计算属性非常类似)

import {createSelect} from "reselect"

// 创建一个缓存数据的函数
let catchFn = createSelect(function(dataList){
  // 数据准备
  return dataList
}, (dataList) => {
  // 数据运算:运算结果会被缓存
  let res = dataList.filter(item => item.bprice > 6000)
  this.setState({
    filterBrands: res
  })
})

(2) repure

参考http://npmjs.orgrepure 模块的使用

你可能感兴趣的:(react.js,javascript,前端)