React4 老夏项目

初始化脚手架结构

public/
  favicon.ico
  index.html
  manifest.json

src/
  assets/
  somponents/
  utils/
  views/
  App.js
  index.js

修改说明
1 把 app.js(改小写), 放在 assets 中
2 把 index.css 的内容接剪切到 app.css  (然后在入口文件中引入合并后的 css文件即可)
3 然后 App.js 中就不需要引入 App的 css文件了  //会在index中被修饰
4 把 logo.svg, 也扔到 asstes 中
5 把 App.js 中的 reportWebVitals 相关删除
6 把 scripts/manifest.json 俩个 png对象的 src删除掉

项目环境常用配置 (需要详细完善, 还有很多不成功)

1 改端口
---------------------------------------------------------------------------
1 script/start.js  //找到端口配置位置, 直接修改
  位置P48: const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
  
2 自定义配置文件 (根目录: react.config.js)
  module.exports = {
    
       
 	devServer: {
    
    
      props: 9000
    }
  }

3 在 script/start.js  (导入自定义的配置文件)
  1 位置: const isInteractive = process.stdout.isTTY; 后面 (P40)
  2 添加代码: const reactConfig = require('../react.config') 
  3 修改端口配置位置的代码
    1 const DEFAULT_PORT = parseInt(process.env.PORT, 10) || reactConfig.devServer.port || 3000;   
---------------------------------------------------------------------------

2 修改入口文件的名字
---------------------------------------------------------------------------
1 fonfig/paths.js
  1 P58, 找到抛出的路径, 对应的: 'src/index' -> 'src/main'
---------------------------------------------------------------------------

3 跨域
---------------------------------------------------------------------------
1 config/webpackDevServer.config.js 中
  1 P17: const reactConfig = require('../react.config')
  2 P106: proxy: reactConfig.devServer.proxy || proxy,
2 然后就可以在, react.config.js 中, 像Vue中配置跨域一样
  devServer: {
    
    
    port: 9000
    proxy: {
    
    
      '/soso': {
    
    
        target: 'https://baidu.com',
        changeOrigin: true
      }
    }
  },
---------------------------------------------------------------------------

4 支持 @ 路径
---------------------------------------------------------------------------
1 config/webpack.config.js 中
  1 P77: const reactConfig = require('../react.config')
  2 P336: ...(reactConfig.alias || {
    
    })

2 react.config.js 中
  1 const path = require('path')
  2 module.exports = {
    
     alias: {
    
    '@': path.resolve(__dirname, './src')}}
---------------------------------------------------------------------------

5 如何支持 Less
---------------------------------------------------------------------------
1 config/webpack.config.js 中
  1 P561: ...(reactConfig.module ? (reactConfig.module.rules || []) : [])  

2 react.config.js 中
  module.exports = {
    
     
    module: {
    
    rules: [{
    
    test: /\.less/, use: ['less-loader']}]}
  }  //注意下载less-loader

3 安装
  1 npm i less-loader -D  //用于加载
  2 npm i less -D  //用于编译
---------------------------------------------------------------------------

5 如何支持 Sass
---------------------------------------------------------------------------
1 安装
  1 npm i sass-loader -D  //用于加载
  2 npm i sass -D  //用于编译
---------------------------------------------------------------------------

6 如何关闭 ES6 line检测错误
---------------------------------------------------------------------------
复制报错最后面的提示 -> 打开 src/package.json -> 找到 "rules" -> 设置 ("粘贴": 0)
---------------------------------------------------------------------------

7 接到项目的第一时间要搞明白的事
---------------------------------------------------------------------------
1 store 全局状态管理
2 utils 里面调接口的等等
3 react.config.js 项目的配置
4 src/views/index.js 路由配置 
5 再看看入口文件 + App.js 文件
---------------------------------------------------------------------------

8 扩展知识
---------------------------------------------------------------------------
1 所有后台管理系统, 必须要有权限管理 (它的做法非常多)
---------------------------------------------------------------------------

布局 layout

1 环境配置
---------------------------------------------------------------------------
1 起步  // antd 需要依赖 Less 
  1 npm i antd -S
  2 src/index.js: import 'antd/dist/antd.css'
  3 按需使用即可

2 定制主题
  1 

3 注意
  1 出现这个警告: index.js:8 You are using a whole package of antd, please use 
  https://www.npmjs.com/package/babel-plugin-import to reduce app bundle size.
  2 根据提示安装使用这个包
    1 npm i babel-plugin-import
    2 config/webpack.config.js 中找到 P425
      原代码: require.resolve('react-refresh/babel'), 后面跟上下面的代码
      +:  ["import", {
    
    "libraryName": "antd", "style": true}]
---------------------------------------------------------------------------

2 定义布局组件
---------------------------------------------------------------------------
  1 src/components/layout/index.js  //定义布局组件
  
  2 src/components/index.js  //管理公共组件
    1 import WeiLayout from './layout'
    2 export {
    
     WeiLayout}
  
  3 src/App.js
    1 import {
    
    WeiLayout} from './components'
    2 const A1 = () => {
    
     return(<div className="app"> <WeiLayout/> </div>)}

  4 修改样式
    1 全局样式 src/assets/app.js
      #root{
    
     position: absolute; top: 0; left: 0; right: 0; bottom: 0; overflow: hidden;}
      .app {
    
    height: 100%; width: 100%;}

    2 组件样式
      1 定义样式 src/components/layout/style.scss
        1 .wei-layout{
    
     height: 100%; .ant-layout {
    
     height: 100%}} //设置高度百分比
      2 使用样式 src/components/layout/index.js
        1 import './style.scss'
        2 export default props => {
    
     return (<div className='wei-layout'></div>)}
---------------------------------------------------------------------------

路由

1 起步
---------------------------------------------------------------------------
1 安装
  1 npm i react-router-dom -S
  2 icon库: npm i @ant-design/icons -S  //可能需要

2 App.js  // 被包裹了才可以使用路由, 一般在这里使用一次即可
  1 import {
    
     HashRouter} from 'react-router-dom'
  2 function App() {
    
     return{
    
     <HashRouter></HashRouter>}}  //包裹组件视图

3 安装代码分割相关模块
  1 npm i @loadable/component -S
  2 npm i @babel/plugin-syntax-dynamic-import -D  // 是否必须, 未知
  3 npm i @babel/preset-react -D  // 是否必须, 未知

4 src/views/index.js  //自定义路由配置文件
  1 import loadable from '@loadable/component'
  2 导入组件
  	1 const Home = loadable(()=>import('./home/index.js'))
  	2 const Redux = loadable(()=>import('./home/Redux'))
  	
  3 配置路由
  	export default [
      {
    
    id: 1, txt: '首页管理', path: '/home', component: Home},
      {
    
    id: 2, txt: 'redux测试', path: '/redux', component: Redux}
    ]

5 布局组件中, 设置菜单导航
  1 src/components/layout/WSider.js
    1 import {
    
     NavLink } from 'react-router-dom'
    2 组件视图: <NavLink to="/home"> home </NavLink>
---------------------------------------------------------------------------

导航菜单+路由关联

1 起步
---------------------------------------------------------------------------
1 安装: npm i @ant-design/icons -S  //需要图标库

2 使用组件基础, 通常需要引入一下三类内容 (三者相互关联)
  1 模块库
  2 组件方法  //通常是 class类组件, 方便定义声明式变量
  3 视图标签
  
3 注意
  1 有些组件的使用, 不被支持 (警告: 在StrictMode中不推荐使用findDOMNode)
    1 解决方式: src/index (入口文件中)
    2 这样挂载 App实例: ReactDOM.render(<App />, document.getElementById('root'))
    
  2 同一个路由导航菜单, 被连续点击出现警告的问题
    1 解决方式: 老夏说不管, 有兴趣再搞

4 使用组件提升, 通过观察发现
  1 一个 <Menu.Item></Menu.Item> 标签, 就是一个小的切换菜单按钮
  2 一个 <SubMenu></SubMenu> 标签, 就是一个二级菜单
  3 简单的调整为自己喜欢的格式 (个人喜好, 方便后面循环的设置)
---------------------------------------------------------------------------

2 导航菜单 (通过自定义路由配置文件循环渲染)
---------------------------------------------------------------------------
1 src/views/index.js  //自定义路由配置文件
  1 由于有二级菜单, 所以准备用二级路由的方式来控制, 菜单导航的跳转
  2 新的自定义路由配置文件格式
    import {
    
    AppstoreOutlined, ..} from '@ant-design/icons'
    import React from 'react'
    const routes = [
      {
    
    
        id: 1, 
        txt: '首页管理', 
        icon: <AppstoreOutlined/>,
        children: [
          {
    
    id: 101, txt: '概括', path: '/home', component: Home},
          {
    
    id: 102, txt: '学习', path: '/redux', component: Redux}
        ]
      },
      {
    
    id: 2, txt: '客户管理', icon: <XXX/>, children: [{
    
    }, {
    
    }]}
    ]

2 src/components/layout/WSider.js  //导航菜单组件文件
  1 import routes from '@/views.index'
  2 封装渲染导航菜单的方法
    1 注意每个二级菜单的 icon 都是不一样的, 我们也要定义在路由配置文件中
    const renderNav = () => {
    
    
      return routes.map(v=>(
        <SubMenu key={
    
    v.id} icon={
    
    v.icon} title={
    
    v.txt}>
          {
    
    v.children.map(e=>(
            <Menu.Item key={
    
    e.id}>
              <Link to={
    
    e.path}>{
    
    e.txt}</Link>
            </Menu.Item>
          ))}
        </SubMenu>
      ))
    }

3 src/components/layout/WContent.js  //布局组件的显示内容的容器组件
  1 import routes from '@/views/index';
  2 定义渲染标签视图的方法  //个人感觉直接写在页面上它不香吗 (少的情况下)
    const renderRoute = () => {
    
    
    const arr = []
    routes.map(v=>{
    
    
      if (v.children) {
    
    
        v.children.map(e=> {
    
    
          arr.push(
            <Route key={
    
    e.id} path={
    
    e.path} component={
    
    e.component}/>
          )
        })
      }
    })
    return arr
  }
---------------------------------------------------------------------------

Redux

1 起步
---------------------------------------------------------------------------
1 创建: src/store/index.js  //全局状态管理文件

2 安装
  npm i redux -S  //提供API
  npm i react-redux -S  //用于关联
  npm i redux-thunk -S  //用于解决 useDispatch 不支持同步的问题 (4-注意事项)
  npm i axios -S  //用于请求数据

3 环境配置
  1 src/App.js
    1 import {
    
    Provider} from 'react-redux'
    2 import store from './store/index.js' 
    3 <Provider store={
    
    store}> 标签, 可当做路由模式的子标签, 包裹住 App.js 的组件视图

4 注意事项
  1 redux 中的 useDispatch, 只支持派发同步的action (不支持异步)
  2 用到异步 -> 需要安装一个第三方库: redux-thunk  //也有其他的库可以辅助解决这个问题
  3 如何使用
    1 初始化全局状态管理文件: src/store/index.js  //详情参照下面的案例
      import {
    
    applyMiddleware} from 'redux'
      import thunk from 'redux-thunk'  //确定是否安装
      const store = createStore(a1, applyMiddleware(thunk))
  4 关于 thunk 的原理解析  //实际上还是处理同步的数据
    1 const dispatch = useDispatch() / dispatch(xx)  //xx只能是一个对象
    2 thunk 用于判断 xx, xx=普通对象直接派发, xx不是对象 thunk会阻止派发
    3 dispatch(xx) 正常情况 xx不是对象就会报错, 有了 redux-thunk就不会报错了
    4 如果 xx 是函数, 就会先调用这个方法
    5 由于通过这个调接口, 有时候会有重复的接口, 我们可以把这些 xx 集合到一个文件中方便管理
    6 新建目录 actions
---------------------------------------------------------------------------

2 基础配置: src/store/index.js  //全局状态管理文件
---------------------------------------------------------------------------
1 引入模块
  import {
    
    createStore, applyMiddleware} from 'redux'
  import thunk from 'redux-thunk'  //确定是否安装
  
2 定义数据
  const initState = {
    
     msg1: 'hello redux'}
  
3 定义方法  //用于修改 state数据
  // action - 业务操作
  // action - 格式 -> action = {type, payload}
  function a1(state=initState, action) {
    
    
    let newState = JSON.parse(JSON.stringify(state))  //深复制, 解决渲染问题 (这种深复制的方法效率不太高)
    switch (action.type) {
    
    
      case 'add':
        //执行 add相关操作, store 是只读的单向数据流
        //该方法的数据更改, 不能同步更新页面渲染, 通过深复制解决
        // state.msg1 += 6
        newState.msg1 += 6
        break; ...
    }
    return newState
  }

4 相关操作
  const store = createStore(a1, applyMiddleware(thunk))
  export default store
---------------------------------------------------------------------------

3 单文件组件中, Redux 高阶函数的使用方式  // 适用于 类组件+函数式组件
---------------------------------------------------------------------------
1 引入模块
  import {
    
    connect} from 'react-redux'  // connect(fn1, fn2)(UI) -> 高阶组件

2 定义组件
  const R = props => {
    
    }

3 定义方法
  //作用 -> 把当前组件要用到的全局状态数据, 映射进来 props.xx 访问
  //形参 -> 是高阶组件 connect() 给的
  //形参 -> store = 全局状态管理文件中定义数据的对象
  function fn1(store) {
    
    
    return {
    
     xx: store.msg1}
  }
  
  //作用 -> 把当前组件要用到的全局状态方法, 映射进来 - (用于修改全局数据)
  //形参 -> 是一个方法, 表示把这个方法赋值给 hh, 并放在 props 上了, 
  //例子 -> 
  function fn2(dispatch) {
    
    
    return {
    
     hh: ()=>dispatch({
    
    type: 'add', payload: 'hello 2021'})}
  }
  
  // 定义修改全局数据的, 函数事件
  const ck1 = () => {
    
    
    //表示把 {type: 'add', payload: 'hello 2021'} 发送出去
    //赋值给, 全局状态管理文件中的, 定义方法中的, action 形参
    props.hh()  
  }

4 抛出组件
  export default connect(fn1, fn2)(R)
---------------------------------------------------------------------------

4 单文件组件中, Redux HOOK的使用方式  // 只适用于函数式组件
---------------------------------------------------------------------------
1 引入模块
  import {
    
     useDispatch, useSelector} from 'react-redux'

2 定义组件
  const A = props => {
    
    
    const msg = useSelector(store=>store.msg)  //得到全局状态的 msg
    const dispatch = useDispatch()  //只支持派发, 同步的 action
    return ()
  }

3 定义方法
  1 定义修改全局数据的, 函数事件
  const ck1 = () => {
    
    
    //表示把 {type: 'add', payload: 'hello 2021'} 发送出去
    //赋值给, 全局状态管理文件中的, 定义方法中的, action 形参
    dispatch({
    
    type: 'add', payload: 'hello 2021'})
  }

4 抛出组件
  export default A
---------------------------------------------------------------------------

5 redux 标准规范写法 
---------------------------------------------------------------------------
1 创建全局状态管理文件的, 子模块: src/store/reducers/hh1.js

  1 定义数据
    const initState = {
    
     msg1: 'hello redux'}

  2 定义方法  //用到 ES6 形参初始值
    export default function A(state=initState, action) {
    
     
      let newState = JSON.parse(JSON.stringify(state))
      switch(action.type) {
    
    
        case 'add':
          newState.msg1 += '66'
          breack;
          default:
      }
      return newState
    }

2 在 src/store/index.js 自定义全局状态管理文件中

  1 导入模块
    import {
    
     createStore, applyMiddleware, combineReducers} from 'redux'
    import home from './reducers/home'  //引入状态管理子模块
    import react from './reducers/react'  // 数据定义在了, 这些导入的模块当中
    
  2 相关操作
    const rootReducer = combineReducers({
    
     home, react})
    const store = createStore(rootReducer, applyMiddleware([thunk]))  //自己加[]报错了
    export default store
    
3 在单文件组件中使用 redux 数据
  1 import {
    
     useDispatch, useSelector} from 'react-redux'
  2 获取全局状态, 封装的子模块 home 中的数据
    cnost A = props => {
    
    const msg = useSelector(store=>store.home.msg)}
  3 调用全局状态方法的时候
    //我们传的参数对象, 这么写死在页面是不合适的
    //因为有些时候, 调用相同的接口, 会涉及到复用, 或, 多次派发任务的时候, 页面会很乱不便于管理
    //为了便于管理和维护, 以及代码的整洁都, 通常我们会新建文件来把, 这些参数对象, 封装起来  
    1 const dispatch = useDispatch()
    2 const ck1 = () => {
    
     dispatch({
    
    type: 'add', payload: 'hello 2021'})}  //这个参数对象

4 封装以及使用 dispatch 参数对象action相关操作 ()
  //理解 1: 统一配置 type 参数 -> 然后基于 type 封装函数 -> 然后基于函数派发任务

  1 封装 action 的type 属性: src/store/actionType.js
    //会用到的地方
    //1 reducer中会用到,因为reducer要根据这个type来执行具体的数据处理
    //2 react组件中会用到,因为action基本上都是在组件中被dispatch过去的
    export default {
    
     ADD: 'ADD', ..}
   
  2 在 src/store/actions/index.js 中  //把所有的 action 参数对象生成器放在这里(也可分模块)
    import type from '../actionType.js'
    function changeMsg(payload) {
    
    
      return {
    
    type: type.ADD, payload}
    }
    export default {
    
     changeMsg}  //任何一个页面需要的话, 都可以使用这个, 参数对象
    
  3 在单文件组件中
    import {
    
    changeMsg} from 'src/store/actions/index.js'
    // dispatch({type: 'add', payload: 'hello 2021'})
    dispatch( changeMsg('hello 2021'))  //实际是派发该函数的返回值, 就是参数对象

  4 在全局状态的子模块中
    import type from '../actionType.js'
    switch(action.type) {
    
    
      case type.ADD:  //此处也应该通过变量定义
        newState.msg1 += '66'
        break;
        default:
    }

5 新建的集中管理文件: src/store/actions
---------------------------------------------------------------------------

请求数据

1 起步
---------------------------------------------------------------------------
1 概念
  1 React 推介, 调接口这些数据等都应该是从外部进来的
 
2 安装
  1 npm i axios S
---------------------------------------------------------------------------

2 呵呵
---------------------------------------------------------------------------
1 请求数据的位置: src/store/actions/hh.js  ??
---------------------------------------------------------------------------

跨域代理

// 脚手架文档 -> Docs -> Back-End Integration -> Proxying in Development

1 第一种处理方式
---------------------------------------------------------------------------
1 安装 
  1 npm i http-proxy-middleware -S

2 新建文件: src/setupProxy.js  //内容如下
  const {
    
     createProxyMiddleware } = require('http-proxy-middleware');
  module.exports = function(app) {
    
    
    // ...
  };

3 配置代理
const {
    
     createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
    
    
  app.use(
    '/api',
    createProxyMiddleware({
    
    
      target: 'http://localhost:5000',
      changeOrigin: true,
    })
  )
}
---------------------------------------------------------------------------

2 第二种处理方式
---------------------------------------------------------------------------
上面的, 项目环境常用配置里面
---------------------------------------------------------------------------

3 第三种处理方式
---------------------------------------------------------------------------

---------------------------------------------------------------------------

商品列表页

1 在项目中添加一个商品列表页模块, 需要干的事
---------------------------------------------------------------------------
1 新建组件 -> 在自定义路由配置文件中 -> 添加路由
2 简单修改组件的全局样式 -> src/components/layout/..  // 如果写了大量的样式就说明方向错了
---------------------------------------------------------------------------

2 启动老师的 node 数据库
---------------------------------------------------------------------------
1 启动数据库: 根据路径启动电脑上的, MongoDB 服务器 (可在全局执行此命令)
  mongod --dbpath "D:\mongodb\data"  
  
2 启动后端代码
  后端文件根目录: npm start
---------------------------------------------------------------------------

3 商品列表, 调接口
---------------------------------------------------------------------------

---------------------------------------------------------------------------

猜你喜欢

转载自blog.csdn.net/weixin_46178697/article/details/113529090