React:kdlzx(APP)实战项目笔记(前端部分-完结)

大家好,我是梅巴哥er。本篇是在写react这个项目时做的流水笔记。这篇是前端部分,也就是基本的页面组件和样式。
项目已完结,等我研究研究github,到时候把完整代码传上去做个分享。

kdlzx项目笔记

1,安装react脚手架,用来搭建项目

  • npm install -g create-react-app

2,创建项目kdlzx

  • create-react-app kdlzx

3,进入安装目录

  • cd kdlzx

4,启动项目查看安装是否成功

  • npm start

5,项目集成less

  • 解包脚手架 npm run eject注:这个命令是为了把隐藏的webpeck文件暴露出来。此操作不可逆,操作须慎重

  • 解包后,启动项目。看下该项目是否正常启动。如果由类似报错: Connot find module '@babel/plugin-transform-react-jsx'。可以尝试解决办法:

    • 删除项目下node_modules文件夹
    • node i
  • 安装less环境

    • 安装less 和 less-loader 。 npm i less less-loader -S

    • 把less 和 less-loader配置到webpack文件中。大致配置三处。

      • 第一处:模仿css来配置less。
        在这里插入图片描述

        代码:

        // 添加配置less模块
        const lessRegex = /\.less$/;
        const lessModuleRegex = /\.module\.less$/;
        
        • 第二处:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q1BiN75t-1598230462709)(C:\Users\Shinelon\AppData\Roaming\Typora\typora-user-images\image-20200820003615974.png)]
          代码:

          lessOptions, // 这个是放在上面括号里面的,看图
              
          // 这里也要添加一下less配置和 less-loader
                {
                      
                      
                  loader: require.resolve('less-loader'),
                  options: lessOptions,
                },
          
          • 第三处:在这里插入图片描述
            代码:

            // 这里模仿sass 配置less和less-loader
            // Adds support for LESS Modules, but using LESS 
            // less start
                        {
                          
                          
                          test: lessRegex,
                          exclude: cssModuleRegex,
                          use: getStyleLoaders({
                          
                          
                            importLoaders: 1,
                            sourceMap: isEnvProduction && shouldUseSourceMap,
                          }),
                          sideEffects: true,
                        },
                        {
                          
                          
                          test: lessModuleRegex,
                          use: getStyleLoaders({
                          
                          
                            importLoaders: 1,
                            sourceMap: isEnvProduction && shouldUseSourceMap,
                            modules: true,
                            getLocalIdent: getCSSModuleLocalIdent,
                          }),
                        }, // less end;
            

            参考:在react中的less配置

6,搭建项目文件

  • 把src文件夹的文件全部删除。自己写入口文件index.js。写入代码,,启动测试。在这里插入图片描述

  • 在src文件夹中,新建文件夹assets。这个文件夹下,放fonts styles images等文件夹。

  • ReactDOM.render()放在App.js里,而不是index.js

  • index.js里放什么呢? index.js是入口文件,在项目中,就像一个清单一样。用来引入核心组件,例如./pages/App,引入初始化的样式,引入全局样式等。

7,测试less的安装和配置情况

  • setyles文件夹,新建core.less文件,加入代码:

    @charset "utf-8";
    
    @color: pink;
    
    body {
        background-color: @color;
    }
    
    

    npm start查看运行结果。样式显示出来,就说明配置成功了。

8,登录页面展示,开始布置登录页面。

9,重置样式、设置页面高度

  • 安装: npm install --save normalize.css

https://github.com/necolas/normalize.css

  • index.js中引入 import 'normalize.css'

10,封装自己的第一个组件: Img组件,把引入img抽离成一个组件

  • 需要抽离组件的原因是, 我们每次引入图片时,前面的路径都是重复的。 比如引入logo图片,import Img from '../assets/images/logo.jpg',其实就是路径'../assets/images/' + '文件名 logo.jpg

  • 需要注意的是,平时引入都是用import, 但是为了方便写组件,在Img.js里,用了require 。 require里包含 重复的路径 + 文件名。 文件名通过父组件LoginPage的参数props来获取。

11,用户名,密码的登录表单

  • 用户名和密码输入框很像,可以做成一个组件来调用

  • 登录,忘记密码,免费注册,游客登录等,都是点击的按钮,也可以做成组件

  • 字体的引入。用阿里的iconfont,把需要的字体下载下来,然后这6个样式文件放入fonts文件夹中。用import引入iconfon.css。一定不要少引入样式文件,不然图标显示不出来的。在这里插入图片描述

  • 设置input输入框的样式。达到美观效果。注意全局样式和局部样式。全局样式写在core.less里面。注意,这里图标是固定的大小和位置,右边输入框是弹性的,所以用到了弹性布局display: flex;

  • 调整输入框里不一样的内容。比如图标、placeholder的属性值、type类型等。用父传子的参数进行调整。 需要注意的是,图标的className的拼接方式*className*={"iconfont icon-" + this.props.iconName},千万不要忘了大括号{ },且要注意大括号的位置。因为js语法都要写在{}里。

  • 4个按钮的组件抽离。边写边考虑4个按钮的不同之处,然后加上相应的参数。通过三元运算符的判断,来决定他们用哪些属性。

  • 注意,按钮的组件,我们用的是双标签,和输入框略微有点区别。 因为这样更容易通过this.props.children来获得按钮里的字。

  • 因为这4个按钮的大小和位置都不一样,所以要通过组件的类和样式,对按钮进行调试和代码简化。需要注意,这里的登录按钮里,<button *className*={ this.props.isFull ? "btn full" : "btn" } >,这里面有对类进行判断,所以写法上要注意。 还有一种模板语言的写法: <button className={ 'btn ${this.props.isFull ? "full" : ""} '}。还有一种用加号+连接的方法: <button className={"btn" + (this.props.isFull ? " full" : " ")},这种方法不要少了小括号哦( ),不然意思就不一样了。

  • 关于空格的小知识点,&nbsp;是不换行空格,受字体宽度影响。 &emsp是一个中文宽度的空格。这两者基本不受字体宽度的影响。详情可看html中的空格标记

  • 关于touch-action的知识点。这个语句在写APP的时候,是必写的。在core.less全局样式文件里,有一个属性touch-action: pan-y;,这个意思是启用单指垂直平移手势,可以用手指拖动页面上下滑动。更多touch-action知识

12,为主页HomePage做准备之移动端UI框架antd-mobile

  • 12.1 项目需要用到移动端的UI框架antd-mobile官方文档)。所以需要先熟悉一下框架应用。

    • 安装 npm install antd-mobile --save

    • index.html中添加html的相关配置。第一个<script>文件是解决手机端比web端延时300ms的问题。第二个<script>文件是解决兼容性问题,如果不支持promise,我就会引入一个可以支持promise的文件。

      <!DOCTYPE html>
      <html>
      <head>
        <!-- set `maximum-scale` for some compatibility issues -->
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
        <script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js"></script>
        <script>
          if ('addEventListener' in document) {
              
              
            document.addEventListener('DOMContentLoaded', function() {
              
              
              FastClick.attach(document.body);
            }, false);
          }
          if(!window.Promise) {
              
              
            document.writeln('<script src="https://as.alipayobjects.com/g/component/es6-promise/3.2.2/es6-promise.min.js"'+'>'+'<'+'/'+'script>');
          }
        </script>
      </head>
      <body></body>
      </html>
      
    • index.js中引入样式import 'antd-mobile/dist/antd-mobile.css'; // or 'antd-mobile/dist/antd-mobile.less'(或者在需要用到该样式的js文件里直接引入)

    • 实现按需加载,这里只介绍官方推荐的简便方法。另一种方法相对麻烦点,不推荐。**按需加载:**只需引入业务中需要的组件即可,未 import 进来的组件不会打包进来。当在开发环境的console控制台中出现在这里插入图片描述
      这样的警告语句时,就要注意了,说明你还在用整个包来加载,现在就需要用按需加载了。

      • 使用 babel-plugin-import(推荐)

        // .babelrc or babel-loader option
        {
                  
                  
          "plugins": [
            ["import", {
                  
                   libraryName: "antd-mobile", style: "css" }] // `style: true` 会加载 less 文件
          ]
        }
        

        然后只需要从antd-mobile中引入需要的模块即可,无需单独引入某个需要的样式。

        操作方法:

        • 首先,安装:npm install babel-plugin-import

        • 然后,打开package.json文件,找到最下面的babel选项。在这里插入图片描述

        • 最后,把代码下面的代码,配置进去。

          "plugins": [
              ["import", {
                      
                       "libraryName": "antd-mobile", "style": "css" }] // `style: true` 会加载 less 文件
            ]
          

          添加后的代码如图:在这里插入图片描述
          注:style的属性为true的时候加载未编译为css的less文件,也就可以改变主题

          如果style:“css”就是加载编译好的css,无法更改主题

        现在,就没有那个警告了。解决。

13,header部分

  • 用到了UI视图中的NavBar SearchBar组件

  • 引入合适的组件代码,修改组件中的样式

  • 用到了display: flex布局,比如撑开盒子flex: 1;,让盒子回归默认样式flex: 0 1 auto关于布局:flex: 0 1 auto啥意思?

  • 用到了组件嵌套。比如:

    <NavBar>
        <SearchBar placeholder="搜索" maxLength={
          
          8} />
    </NavBar>
    
  • 用到了less样式内的引入和抽离。比如 背景颜色很多用到了background-color: #0A338F。那就把这个样式抽离出来,专门写到global.less里。 有哪里需要,就用@import引入使用。

  • 用到了对antd-mobile框架自带样式的调整。调整方法就是,在页面F12,找到对应的样式,然后在less文件中进行直接写入修改。

14,banner部分(也叫走马灯,轮播图,焦点图等)

  • 用到了UI框架的走马灯组件Carousel
  • 需要把两翼空白的组件标签<WingBlank size='md'>...</WingBlank>去掉。让图片把banner部分的容器铺满,不留空白。
  • this.setState里面,把图片换上自己的大小合适的图片。

15,学科导航

  • 用到了UI框架的Flex组件
  • 用到了精灵图,用backgroundPositionX来选择精灵图中的具体的对应图片。
  • 我没有精灵图,直接截了图片的,看着有点难看。。。

16,小列表资讯

  • 这部分是写在HomePage.js里的。暂时放这里。
  • 用到了数组.map((v, k) => { }),进行遍历创建列表。v是数组中的每一项元素k对应的是id或者有顺序的数字,拿来给key用的
  • 创建的一个小列表里,包含左边的图片,和右边的文字。所以用到了UI框架<Flex />
  • 一个小列表里的左右布局,用到了flex。 左边需要图片盒子回归到默认大小,而不是让左右两边平均分摊小列表的大小,所以用到了flex: 0 1 auto。而右边的文字部分,是要把右边部分撑开的,所以用到了flex: 1;
  • UI框架<Flex />中,右边的文字默认是居中的,也就是align-items: center,但是我们需要修改成文字是挨着顶部的,也就是默认状态。即align-items: stretch;点击了解耕多关于align-items

17,Tab栏

  • 用到了<Tabs />UI框架。注意这里的引入,还跟了个const tabs={ ... }
  • 用到了<List />UI框架中的Items。注意这里引入的是List,同时,还需要加上const Item = List.Item列表引入。
  • 用到了<Flex />UI框架,还有font字体。都是之前用到过的了。

18,主页HomePage尾部工作

  • 这个尾部的框,和头部的框是相似的,所以可以套用<Header />组件。
  • 通过三元运算符,做个判断,把组件中不要的部分去掉。
  • 复习一下行内标签添加style的方式:<div style={ { width: "100%", textAlign: "right"}} >

19,长列表页ListPage

  • 首先是头部,直接放上<Header />组件。拿过来就能用。这也是组件的好处,
  • 下面就是长列表了。这个是真的长。而且UI框架里的<ListView />代码,也是真滴长啊。
  • 这个组件拿过来其实也能直接用。但是一个小的难点在于,要想把小列表设计成自己想要的样式,需要做些什么。
  • 对长组件进行修改。仔细看组件代码,找到这里,这就是我们要放置自己对列表设计的地方。const obj = data[index--]; return ( <**SubListItem** *obj*={ obj } /> )。这个return里包含的就是每个小列表的样子。
  • 代码越写越多,越来越长。精简是必要的。对于组件,要尽可能的抽离和简化,那么 对于样式,也是如此。比如样式的导入和引用。熟悉less的入门知识就必不可少了。

20,详情页DetailPage

  • 头部直接用UI框架的<Header />组件。但是,有些不一样的地方需要调整。需要加一个判断–调用者是否是详情页isDetail,如果是详情页,就用详情页的头部属性。用到了三元运算符。这里有两种写法,其中 第二种比较好理解。
  • 文章部分,用到了<article>和内容<content>标签。这部分就是往里塞<p>标签,比较好理解。
  • 相关资讯,直接调用写好的组件<SubList />
  • 热门评论。这块和相关资讯外形及其相似。 但是还有不少不同点。所以这块是自己写的。用到了<Flex />布局框架。细心,多练。这些知识,跟着写一遍两边,肯定也达不到熟练的程度。需要自己多写。

加一个判断–调用者是否是详情页isDetail,如果是详情页,就用详情页的头部属性。用到了三元运算符。这里有两种写法,其中 第二种比较好理解。

  • 文章部分,用到了<article>和内容<content>标签。这部分就是往里塞<p>标签,比较好理解。
  • 相关资讯,直接调用写好的组件<SubList />
  • 热门评论。这块和相关资讯外形及其相似。 但是还有不少不同点。所以这块是自己写的。用到了<Flex />布局框架。细心,多练。这些知识,跟着写一遍两边,肯定也达不到熟练的程度。需要自己多写。

21,添加路由

  • 安装 npm install react-router-dom
  • 在Login页面,点击登录跳转到首页/home
  • 点击home中的学科导航,跳转到长列表页面/list
  • 点击list的小列表内容,跳转到详情页/detail
  • 给logo图片加上<Link to='/home'>,点击页面的Logo都可以回到首页、
  • Header的返回箭头加上点击事件,点击后都可以返回上一页。onLeftClick={() => window.history.go(-1) } 或者this.props.history.goBack()(注意这里的props需要继承父组件)
  • 需要注意这里的写history的方式,这里在官方文档是更新了的。
  • 遇到的问题,页面跳转后,小列表内容里的文字不见了。F12查看,文字还在,但是没显示。经查看,可能是a标签的color给的是白色导致的。所以给小列表的样式加上字体颜色就解决了。

22,受控组件

  • 受控组件,是让login页面的输入框变成受控组件。组件的核心属性valueonChange

  • 用户输入的信息,可以实时监测,方便对输入框的内容进行判断,是否符合输入要求。

  • 写受控组件有个小技巧。正常情况下,login的form是一个组件,输入框是子组件,应该是输入框的变化,传给父组件login的form表单,也就是数据的子传父。这就有点麻烦。那就改变一下方法,变成父传子,就会方便很多。 在login页面组件里写constructor构造函数,初始化状态this.state,添加valueonChange属性。然后在子组件输入框中,添加value={ this.props.value }onChange={ this.props.onChange }来接收父组件传来的value和onChange。

  • 简写形式。写好之后,input输入框是这样的:

    <input type={
          
          this.props.type} placeholder={
          
          this.props.placeholder}
                    value={
          
           this.props.value }
                    onChange={
          
           this.props.onChange } />
    

    可以看出来,input里的属性,都是来自于父组件。所以,这里可以简写为:<input {...this.props} />。这表示 输入框的属性全部继承父组件的属性。

  • 注意一个细节。给icon加不同名字时,要写做iconname,而不要写做iconName

23,使用axios发送请求后跳转到首页(而不是用Link)

  • 在父组件login里面,写入onClick属性,建立点击函数handleClick。 然后把点击事件传给子组件formbtn,onClick={ this.props.onClick }

  • 在父组件的handleClick函数里,判断点击登录时,用户输入的用户名和密码是否符合要求。

  • 在父组件的handleClick函数里,用axios向后台发起登录请求。

  • 安装axios: npm install axios

  • 引入axios: import axios from 'axios'

  • 发起请求 ,以get为例。axios.get('路径', 参数数据).then(...).catch(...)

  • 跳转方法:

    • this.props.history.push('/home') 有浏览记录的跳转
    • this.props.history.replace('/home')没有浏览记录的跳转
  • 跳转时需要注意,需要阻止按钮在浏览器的默认事件。e.preventDefault() 不然跳转不过去。

  • 跳转提示。用到了antd-mobile{ Toast }组件的API。先引入 import { Toast } from 'antd-mobile',然后直接引用不同的API即可。括号里面是参数,可以根据自己的需求 进行修改。

    • 跳转成功:Toast.success(content, duration, onClose, mask)
    • 跳转失败:Toast.fail(content, duration, onClose, mask)
    • 跳转信息:…

24,前后端联调

token知识,不太懂。 稍后回去补习node的知识。

25,subjec数据渲染

  • subject.json里的数据,渲染到Subject.js组件里。
  • componentDidMount() { }里发起请求。(这个需要记住
  • 请求需要用到axios。所以先引入import axios from 'axios'
  • 用到了数据变化,所以需要把constructor、super、this.state写出来
  • 在发出的请求体里 写上this.setState状态的变化,获取到subject.json的数据
  • map遍历生成每一项。这里需要注意的是,如果一次性把7条数据都生成,就都在同一行显示了。所以这里用if()进行判断。每4个渲染一次 生成一行。然后下面的4个再渲染一次。

26,subject组件中的路由传参

  • 列表页一般都有很多页。比如subject学科就有7个学科。点击每一个学科,怎么跳转到对应的学科列表内容呢?
  • 这就用到了传参。 传参就是传的id值
  • 这个id值在哪里呢?在this.props的match的params里面。
  • 怎么识别每一个列表页呢? 这就用到了列表id。在Route的路径中修改为/list:id,然后把a连接中的id加进去。 就给每一个url,加入了id

27,redux

  • Redux是JS状态容器,提供项目中的状态管理

  • Redux的三个重要概念:

    • store:数据仓库。存储数据用的,把数据都放在仓库里。
    • action:组件的动作名和动作的定义。它决定了如何修改仓库数据
    • dispatch:执行相应的action。它决定了何时修改仓库数据
  • 安装redux: npm install redux

  • 引入创建仓库 import {createStore} from redux

  • 请一个管理员reducer,来管理仓库store。管理员必须是函数

    const reducer = (state, action) => {
          
          
        ...
        return {
          
          
        	要传入的数据
            //例如 num1: 20
        }
    }
    
  • 创建一个仓库store,把仓库管理员请来管理仓库。

    const store = createStore(reducer)
    
  • 在组件中,获取初始state。

    constructor(props) {
          
          
        super(props)
        // 在这里取初始的state数据
        this.state = store.getState() 
    }
    
  • 在组件的return里写入数据

    render() {
          
          
        return (
        	<div>
            	<p>{
          
           this.state.num1 }</p>
            </div>
        )
    }
    
  • 处理事件。

    <div>
    	<button onClick={
          
          this.changeNumUp}>增加</button>
    </div>
    
  • 事件函数changeNumUp。修改数据的时候,需要调用store中的dispatch方法,把新的值放在action对象中传进去。 每次调用dispatch,会在内部调用仓库管理员reducer

    changeNumUp = (e) => {
          
          
        const action = {
          
          
            type: 'up', // 修改数据的动作名称
            value: this.state.num1 + 1 // 修改数据的方式,每次修改都让这个数据加1
        }
        store.dispatch(action) // 调用仓库store的dispatch方法
    }
    storeChange=(e) => {
          
          
        this.setState(store.getState())
    }
    
  • 回到管理员reducer,把action对象深拷贝到newState。这时reducer中的state发生了变化,但是组件中的state还没有变化,也就是渲染到页面的数据还是显示原来的数据。

    const reducer = (state, action) => {
          
          
        if(action.type === 'up') {
          
          
            let newState = JSON.parse(JSON.stringfy(state)) // 做深拷贝
            newState.num1 = action.value
            return newState
        }
        // 这里是定义初始的state
        return {
          
          
            num1: 20
        }
    }
    
  • store订阅。一旦store数据发生改变,则执行storeChange函数里面的状态。这一步写在this.state的下面:

    store.subscribe(this.storeChange)
    // subscribe监听每次修改情况。然后把变化后的数据渲染到页面
    

28,react-redux

  • 为了方便使用,redux的作者,专门给react封装了一个库–react-redux
  • react-redux提供了API。并且遵守它的组件拆分规范。
  • react-redux将所有组件拆分为两大类:
    • UI组件
    • 容器组件
  • UI组件
    • 只负责UI的呈现,不带有任何业务逻辑
    • 没有状态(即不使用this.state这个变量)
    • 所有数据都由参数(this.props)提供
    • 不使用任何Redux的API
  • 容器组件
    • 负责管理数据和业务逻辑,不负责UI的呈现
    • 带有内部状态
    • 使用Redux的API
  • connect()
    • react-redux提供了connect()方法,用于从UI组件生成容器组件。把两种组件连接起来。
  • Provide组件
    • react-redux提供Provide组件。它可以让容器组件拿到state状态数据。<Provide></Provide>包裹了原来项目的根组件。
  • 安装react-redux:npm install react-redux
  • 注意,为了修改一个数据,要用到以上这么多组件和方法,不是更复杂了吗?所以,这就牵扯到一个问题:到底什么时候需要用到react-redux呢? 当然是有复杂的数据需要传递和修改时才用到它,而不是什么情况下都去用它。如果项目本身复杂程度不高,就不需要用它了。

29,项目中使用react-redux----使用它渲染数据

  • 以学科列表Subject.js 为例,第一步,先进入到顶级组件(就是要被Provide包裹的组件)App.js文件里

  • 第二步,在顶级组件里,引入初始状态数据defaultState。先请一个管理员reducer来,然后创建一个仓库store,交给这个管理员来管理createStore(reducer)

    const defaultState = {
          
          
        subject_data: []
    }
    // 请一个仓库管理员(管理员必须是一个函数)
    const reducer = (state = defaultState, action) => {
          
          
        return state
    }
    // 创建一个仓库,把上面的管理员请来管理这个仓库
    const store = createStore(reducer)
    
  • 第三步,继续在顶级组件里操作,把<Router></Router>包裹在<Provider store={ store } ></Provider>里。

    const router2 = <Provider store={
          
           store } >
        <Router history={
          
           history } >
            <Route exact path='/' component={
          
           LoginPage } />
            <Route path='/home' component={
          
           HomePage } />
            <Route path='/list:subjectId' component={
          
           ListPage } />
            <Route path='/detail' component={
          
           DetailPage } />
        </Router>
    </Provider>
    
  • 第四步,从reduxreact-redux分别引入需要用到的方法和组件。

    import {
          
           createStore } from 'redux'
    import {
          
           Provider } from 'react-redux'
    // 注意: createStore 是从redux里引入的
    // Provider是从react-redux中引入的
    
  • 第五步,connect连接。哪个文件需要用到仓库里的数据,就到那个文件里建立connect连接。这里的项目中,仓库是放在顶级组件App.js里的,学科列表文件Subject.js需要用到仓库里的数据,那就到Subject.js文件里建立连接。connect(定义state数据转props数据的函数,修改数据的函数)(用仓库数据的这个组件)在Subject.js中的代码是:

    // 在文件最上部,引入connect
    import {
          
           connect } from 'react-redux'
    
    //然后在文件的最下部
    // 定义state数据转props数据的函数
    const mapStateToProps = (state) => {
          
          
        return {
          
          
            subject_data: state.subject_data
        }
    }
    // 和仓库数据建立连接
    export default connect(mapStateToProps, null)(Subject)
    // 这里的修改数据函数还没写,所以这个位置先写成null了
    
  • 第六步:Subject.js现在是一个UI组件了,所以这里面不能有this.state了,而是要把所有需要用this.state的地方,都改成this.props。(而对应的,App.js就是一个容器组件了,这里面写有状态和API,而不负责UI呈现。于是,这样就完成了组件拆分。)

  • 第七步,修改数据。

    • Subject.js中,创建一个修改数据的函数mapDispatchToProps
    • 创建action,用来说明修改数据的方式
    • 调用dispatch(action)方法。按照action说明的方式,对数据进行修改。
    • axios发起的请求里,调用这个包含action的方法。表示当发起请求时,把数据传给action的value,然后对数据进行修改。
    • connect中的修改数据函数补充进去
    • 在管理员reducer中,进行深拷贝修改的数据

具体代码如下:

// Subject.js

componentDidMount() {
    
    
        // 在这里面发起请求
        axios.get('/server/subject.json')
        .then((res) =>{
    
    
            // 拿到subject.json中的数据
            console.log(res.data)

            this.props.init_subject_data(res.data)
            // res.data就是json数据。
            // 把这个数据以实参的形式传给init_subject_data这个函数
            
        })
    }


// 用dispatch修改数据
const mapDispatchToProps = (dispatch) => {
    
    
    return {
    
    
        // 这里不能使用箭头函数 哦
        init_subject_data (res_data) {
    
    
            // 创建一个action,来说明应该如何修改数据
            let action = {
    
    
                type: 'init_subject_data',
                value: res_data
            }
            dispatch(action)
        }
    }
}

// 和仓库数据建立连接
export default connect(mapStateToProps, mapDispatchToProps)(Subject)

// App.js

// 请一个仓库管理员(管理员必须是一个函数)
// 在这里面进行深拷贝,管理仓库
const reducer = (state = defaultState, action) => {
    
    
    if (action.type === 'init_subject_data') {
    
    
        let newState = JSON.parse(JSON.stringify(state)) // 深拷贝数据
        newState.subject_data = action.value
        return newState
    }

    return state
}

30,项目部署

  • 购买服务器

    • 选择云服务器:阿里云服务器
    • 个人免费获取:[阿里云试用中心] (https://free.aliyun.com/)
  • 配置服务器

  • 远程连接到服务器

    • 打开终端输入: ssh root@公网ip地址
    • 输入密码
    • 看到root@xxxxxxxxxxxxxxxxx:-#,表示登录成功
  • 部署项目需要的环境

  • 上传项目npm build,得到一个build文件夹

  • build文件夹传到云服务端

  • 启动项目

----------------------------------------------End----------------------------------------------------------

---------------------------前端这块,到此基本结束。接下来是后端以及交互的内容。

猜你喜欢

转载自blog.csdn.net/tuzi007a/article/details/108192596
今日推荐