react学习笔记一:入门级小白到脚手架(create-react-app)开发项目

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 这篇文章是React的学习笔记,覆盖了从React的基础用法到高级特性,包括组件化、状态管理、生命周期、虚拟DOM等主题,适合React初学者参考。

前言

公司实习的地方,使用react,然后打算学习一下react,并把基础知识点整理一下,毕业设计的前端,也使用react来搭建前端框架。
这里主要有如下react基础知识点:

  1. jsx语法
  2. 组件定义的两种方式:类和方法
  3. 组件三大属性:state、props、ref(这个为标签属性)
  4. 组件的组合
  5. 标签的受控组件和非受控组件
  6. react的生命周期
  7. react应用(基于create-react-app脚手架)
  8. react-axios
  9. react-router
  10. react-UI:antdesign
    最重要的一个 没讲:redux
    代码都已上库到GitHub上。
    传送门https://github.com/fengfanli/react-study

一、helloworld

先使用react写一个helloworld,体验一下。
先导入react开发版本js,有三个,react.development.js、react-dom.development.js、babel.min.js
react.js:React 的核心库
react-dom.js:提供操作DOM 的react 扩展库
babel.js:为babel库,两个作用1、将es6语法转化为es5,2、解析JSX语法代码为纯JS 语法代码的库(这里使用的是后者语法)

<body>
    <div id="example"></div>
    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/babel">  // 声明:告诉babel.js这里有jsx语法
        // 1、创建虚拟DOM元素对象
        var vDom = <h1>Hello React</h1>    // 不是字符串  jsx 语法
        // 2、将虚拟DOM渲染到页面真实DOM容器中
        ReactDOM.render(vDom, document.getElementById("example"))
    </script>
</body>

页面:
在这里插入图片描述
步骤(重点学习的地方):
在< script type=“text/babel”> 中编写:声明:告诉babel.js这里有jsx语法
2. 创建虚拟DOM元素对象:就是定义一个变量,将HTML标签赋值于变量
3. 将虚拟DOM渲染到页面真实DOM容器中

技术点:

  1. jsx语法:var vDom = <h1>Hello React</h1>
  2. 渲染语法:ReactDOM.render(vDom, document.getElementById("example"))

二、React jsx

2.1 jsx

  1. 全称: JavaScript XML
  2. react定义的一种类似于XML的JS扩展语法: XML+JS
  3. 作用: 用来创建react虚拟DOM(元素)对象
    a. var ele = < h1>Hello JSX!< /h1>
    b. 注意1: 它不是字符串, 也不是HTML/XML标签
    c. 注意2: 它最终产生的就是一个JS对象
  4. 标签名任意: HTML标签或其它标签
  5. 标签属性任意: HTML标签属性或其它
  6. 基本语法规则
    a. 遇到 <开头的代码, 以标签的语法解析: html同名标签转换为html同名元素, 其它标签需要特别解析
    b. 遇到以 { 开头的代码,以JS语法解析: 标签中的js代码必须用{ }包含
  7. babel.js的作用
    a. 浏览器不能直接解析JSX代码, 需要babel转译为纯JS的代码才能运行
    b. 只要用了JSX,都要加上type=“text/babel”, 声明需要babel来处理

2.2 动态展示列表数据

功能: 在页面中遍历一个数组,将其显示在页面中。
问题: 如何将一个数据的数组 转换为 一个标签的数组 很常用,使用数组的map() 方法 和 箭头函数

    <div id="example1"></div>
    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/babel">
        /**
        * 功能:动态展示列表数据
        * 问题:如何将一个数据的数组 转换为 一个标签的数组   很常用
        *      使用数组的map() 方法 和 箭头函数
        * */
        const names = ['jQuery', 'zepto', 'angular', 'react', 'vue']
        // 1、创建虚拟DOM
        // li 标签一定要带 key属性,而且还不能一样 否则警告
        const ul = (
            <ul>
                {names.map(name=> <li key={name}>{name}</li>)}
            </ul>
        )
        // 2、渲染虚拟DOM
        ReactDOM.render(ul, document.getElementById('example'))
    </script>

页面:
在这里插入图片描述
步骤:

  1. 创建虚拟DOM
    使用 {} 大括号写法,在里面写js语法,将数组遍历。
  2. 渲染虚拟DOM(固定形式写法,将定义好的jsx虚拟dom渲染到 真实dom上)

技术点:
3. {} 大括号写法:
4. 数组方法map():js方法,是对数组的遍历,里面为回调函数,方法形式:
map(value):value 为数组的值,
map(value, index):value 为数组的值,index为数组下标

2.3 虚拟dom创建的两种方式

  1. 使用原生js方法:const vDom1 = React.createElement(‘h1’, {id:‘myTitle’},‘hello’)
  2. 使用jsx方法:const vDom2 = < h3 id={myId.toUpperCase()}>{msg.toLowerCase()}< /h3>

2.4 代码实例

<body>
    <div id="test01"></div>
    <div id="test02"></div>
    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/javascript">
        /**
         * 需求,两种方式实现虚拟DOM的创建
         * 1、使用原生js方法:const vDom1 = React.createElement('h1', {id:'myTitle'},'hello')
         * 2、使用jsx方法:const vDom2 = <h3 id={myId.toUpperCase()}>{msg.toLowerCase()}</h3>
         */
        const msg = 'I Like you!'
        const myId = 'fengfanli'
        // 1、创建虚拟DOM元素对象
        // const element = React.createElement('h1', {id:'myTitle'},'hello')
        const vDom1 = React.createElement('h2', {id: myId.toLowerCase()}, msg.toUpperCase())
        // debugger
        // 2、将虚拟DOM渲染到页面真实DOM容器中
        ReactDOM.render(vDom1, document.getElementById('test01'))
    </script>
    <script type="text/babel">
        // 1、创建虚拟DOM元素对象
        const vDom2 = <h3 id={myId.toUpperCase()}>{msg.toLowerCase()}</h3>
        // debugger
        // 2、将虚拟DOM渲染到页面真实DOM容器中
        ReactDOM.render(vDom2, document.getElementById('test02'))
    </script>
</body>

页面:
在这里插入图片描述

2.5 步骤

  1. 创建虚拟dom
  2. 渲染虚拟dom

2.6 技术点

  1. 渲染虚拟dom的两种方法:原生js和jsx

三、组件化、模块化

3.1 组件

  1. 理解: 用来实现特定(局部)功能效果的代码集合(html/css/js)
  2. 为什么: 一个界面的功能更复杂
  3. 作用: 复用编码, 简化项目编码, 提高运行效率

3.2 组件化

当应用是以多组件的方式实现, 这个应用就是一个组件化的应用。
在这里插入图片描述

3.3 模块

  1. 理解: 向外提供特定功能的js程序, 一般就是一个js文件
  2. 为什么: js代码更多更复杂
  3. 作用: 复用js, 简化js的编写, 提高js运行效率

3.4 模块化

当应用的js都以模块来编写的, 这个应用就是一个模块化的应用

四、组件定义两种方式

  1. 方式一:使用方法定义,没有状态用此种方式(简单组件)
  2. 方式二:使用定义,(复杂组件)

4.1 代码实例

<body>
    <div id="example1"></div>
    <div id="example2"></div>
    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/babel">
        /**
         * 组件定义的两种方式
         * 1、使用方法定义,没有状态用此种方式(简单组件)
         * 2、使用类定义,(复杂组件)
         */
        // 1.定义组件
        //方式1: 工厂函数组件(简单组件):没有状态的组件
        function MyComponent() {
            return <h2>工厂函数组件(简单组件)</h2>
        }

        //方式2:  ES6类组件(复杂组件)
        class MyComponent2 extends React.Component{
            render(){
                console.log(this)
                return <h2>工厂函数组件(简单组件)</h2>
            }
        }
        // 2.渲染组件方式
        ReactDOM.render(<MyComponent />, document.getElementById('example1'))
        ReactDOM.render(<MyComponent2 />, document.getElementById('example2'))
    </script>
</body>

页面:
在这里插入图片描述

4.2 技术点

  1. 两种定义组件的方式:方法(简单组件)、类(复杂组件)
  2. render()方法,在里面写UI,

五、组件三个属性:state、props、refs

5.1 component_state

5.1.1 需求说明

自定义组件,功能说明如下

  1. 显示 h2 标题,初始文本为:你喜欢我
  2. 点击标题更新为:我喜欢你

5.1.2 state

  1. state是组件对象最重要的属性, 值是对象(可以包含多个数据)

  2. 组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)

  3. 初始化状态:

  constructor (props) {
    super(props)
    this.state = {
      stateProp1 : value1,
      stateProp2 : value2
    }
  }

4、 读取某个状态值
this.state.statePropertyName // statePropertyName 自定义名称
5、 更新状态---->组件界面更新

  this.setState({
    stateProp1 : value1,
    stateProp2 : value2
  })

5.1.2 代码实例

<body>
    <div id="example"></div>
    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/babel">
    /**
    * 需求:自定义组件,功能说明如下
    * 1. 显示 h2 标题,初始文本为:你喜欢我
    * 2. 点击标题更新为:我喜欢你
    * */
    // 1.定义组件
    class Like extends React.Component{
        // 2)、构造器
        constructor(props){
            super(props)
            // 初始化状态
            this.state = {
                isLikeMe: false
            }
            // 将新增方法中的this 强制绑定为组件对象
            this.handleClick = this.handleClick.bind(this)
        }
        // 1)、重写组件类的方法
        render(){
            // 读取状态
            const {isLikeMe} = this.state  // 第二种方式
            return <h2 onClick={this.handleClick}>{isLikeMe?'你喜欢我':'我喜欢你'}</h2>
        }
        // 3)、新添加的方法:内部的 this 默认不是组件对象,而是 undefined, 所以要在 构造器中 绑定方法
        handleClick(){
            console.log('handleClick()',this)
            // 得到原有状态 并取反
            const isLikeMe = !this.state.isLikeMe
            //更新状态
            this.setState({isLikeMe})
        }
    }
    // 2.渲染组件
    ReactDOM.render(<Like />, document.getElementById('example'))
</script>
</body>

5.1.3 步骤

  1. 定义组件类
  2. 编写**render()**方法,在这里写UI组件。
  3. 编写构造器,和里面的state属性初始化。
  4. 然后在编写点击事件这里需要注意这个方法需要绑定到类上,在构造器上进行bind()方法绑定。

5.1.4 步骤、技术点

  1. 编写组件类
  2. render方法
  3. constructor构造器、state属性
  4. 编写点击事件,在构造器bind绑定,注意更新state的方法和获取state的关键字
  5. 渲染组件:ReactDOM.render()

5.2 component_props

5.2.1 需求说明

需求: 自定义用来显示一个人员信息的组件
1). 姓名必须指定
2). 如果性别没有指定, 默认为男
3). 如果年龄没有指定, 默认为18

5.2.2 props

理解

  1. 每个组件对象都会有props(properties的简写)属性
  2. 组件标签的所有属性都保存在props中

作用

  1. 通过标签属性 从组件外向组件内 传递变化的数据
  2. 注意: 组件内部不要修改props数据

编码操作

  1. 内部读取某个属性值
    this.props.propertyName
  2. 对props中的属性值进行类型限制必要性限制
Person.propTypes = {
name: React.PropTypes.string.isRequired,
age: React.PropTypes.number.isRequired
}

3、 扩展属性: 将对象的所有属性通过props传递
<Person {...person}/>
4、 默认属性值

Person.defaultProps = {
name: 'Mary'
}

5、 组件类的构造函数

constructor (props) {
super(props)
console.log(props) // 查看所有属性
}

5.2.3 代码实例

<body>
<div id="example1"></div>
<div id="example2"></div>
<div id="example3"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
    /**
     * props属性 和 prop-types.js    prop-types.js: 对值进行设定
     * 需求:自定义用来显示一个人员信息的组件,效果如页面,说明
     * 1、如果性别没有指定,默认为男
     * 2、如果年龄没有指定,默认为18
     */
    // 1、定义组件
    /**
     * 使用 对象组件
     * 组件对象有三个 state props refs
     **/
    class Person extends React.Component{
        render(){
            console.log(this)
            return(
                <ul>
                    <li>姓名:{this.props.name}</li>
                    <li>年龄:{this.props.age}</li>
                    <li>性别:{this.props.sex}</li>
                </ul>
            )
        }
    }
    // 指定属性 默认值
    Person.defaultProps = {
        age: 18,
        sex: '男'
    }
    // 对 props 中的属性值进行类型限制和必要性限制
    Person.propTypes = {
        name: PropTypes.string.isRequired,
        age: PropTypes.number
    }

    // 2、渲染组件
    const p1 = {
        name: 'Tom',
        age: 18,
        sex: '女'
    }
    ReactDOM.render(<Person name={p1.name} age={p1.age} sex={p1.sex} />, document.getElementById("example1"))

    const p2 = {
        name: 'Jack',
    }
    ReactDOM.render(<Person name={p2.name} age={20}  />, document.getElementById("example2"))

    /**
     *  ... 的作用
     *  1、打包
     *  function fn(...as){}  fn(1, 2, 3)  : 打包的意思
     *  2、解包
     *  const arr1 = [1, 2, 3]  const arr2 = [6, ...arr1, 9]  :解包的意思
     *
     * @type {
  {name: string}}
     */
    const p3 = {
        name: 'Feng',
    }
    ReactDOM.render(<Person  {...p3} />, document.getElementById("example3"))
</script>
</body>

页面:
在这里插入图片描述

5.2.4 步骤、技术点

新添加了一个js:prop-types,这个库是在子组件中,对父组件传给子组件的属性值进行加以设定。

  1. 在渲染虚拟dom,ReactDOM.render(<Person />, document.getElementById("example3"))
    向 HTML标签一样,添加属性,往里面传值,在组件类 Person中通过 this.props.属性名获取值。
  2. 扩展运算符(三点运算符)...将对象的所有属性通过props传递

5.2.5 问题:区别state和props

请区别一下组件的props和state属性

  1. state: 组件自身内部可变化的数据
  2. props: 从组件外部向组件内部传递数据, 组件内部只读不修改

5.3 component_refs

5.3.1 需求描述

需求: 自定义组件, 功能说明如下:

  1. 点击按钮, 提示第一个输入框中的值
  2. 当第2个输入框失去焦点时, 提示这个输入框中的值

5.3.2 refs属性

  1. 组件内的标签都可以定义ref属性来标识自己
    a. <input type="text" ref={input => this.msgInput = input}/>
    b. 回调函数在组件初始化渲染完或卸载时自动调用

  2. 在组件中可以通过this.msgInput来得到对应的真实DOM元素

  3. 作用: 通过ref获取组件内容特定标签对象, 进行读取其相关数据

5.3.3 事件处理

  1. 通过onXxx属性指定组件的事件处理函数(注意大小写)
    a. React使用的是自定义(合成)事件, 而不是使用的原生DOM事件
    b. React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)
  2. 通过event.target得到发生事件的DOM元素对象
<input onFocus={this.handleClick}/>
handleFocus(event) {
event.target  //返回input对象
}

5.3.4 强烈注意

  1. 组件内置的方法中的this为组件对象

  2. 在组件类中自定义的方法中this为null
    a. 强制绑定this: 通过函数对象的bind()
    b. 箭头函数(ES6模块化编码时才能使用)

5.3.5 代码实例

<body>
<div id="example1"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
        /**
         * 事件 与 ref
         * 需求:自定义组件,功能说明
         * 1、界面如图所示
         * 2、点击按钮,提示第一个输入框中的值
         * 3、当第二个输入框失去焦点时,提示这个输入框中的值
         */
        // 1、创建组件
    class MyComponent extends React.Component {
        constructor(props) {
            super(props)
            this.showInput = this.showInput.bind(this)
            this.handleBlur = this.handleBlur.bind(this)
        }

        showInput() {
            const value = this.refs.content.value;
            alert(value)
            alert(this.input.value)
        }
        // 事件都有一个固定的形参
        handleBlur(event) {
            console.log(event)
            console.log(event.target)   //指的是标签
            // event.target : 指的是 input 表单框
            alert(event.target.value)
        }

        /* 最后一个比较特别,操作的 dom 元素,是发生事件的元素。*/
        render() {
            return (
                <div>
                    <input type="text" ref="content"/> &nbsp;&nbsp;
                    <input type="text" ref={input => this.input = input}/> &nbsp;&nbsp;
                    <button onClick={this.showInput}>提升输入</button>
                    &nbsp;&nbsp;
                    <input type="text" onBlur={this.handleBlur} placeholder="失去焦点提示内容"/>
                </div>
            )
        }
    }

    // 2、渲染组件
    ReactDOM.render(<MyComponent/>, document.getElementById("example1"))
</script>
</body>

展示:
在这里插入图片描述

5.3.6 步骤、技术点

大体步骤与前一样

  1. 点击事件要在constructor构造器中进行bind()方法绑定。
  2. ref使用方法一:ref属性的value值为唯一值,然后在点击事件中 通过 this.refs.ref属性名获取
  3. ref使用方法二:ref属性的value值为回调函数{input => this.inputMsg = input},返回一个,然后在点击事件中 通过 this.inputMsg 获取

六、组件的组合

6.1 需求描述

功能: 组件化实现此功能

  1. 显示所有todo列表
  2. 输入文本, 点击按钮显示到列表的首位, 并清除输入的文本
    在这里插入图片描述

6.2 代码实例

<body>
<div id="example"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">

    /**
     * 界面中有一个文本框和按钮,按钮中显示下面的几个数据
     * 下面是一个 ul 列表,默认遍历 数组中的数据。
     * 事件:点击按钮,文本框中的数据出现在下面中的 ul 列表中
     */

    /**
     *问题:数据保存在哪个组件内?
     *     看数据是某个组件需要(给它),还是某些组件需要(给共同的父组件)
     *问题2:需要在子组件中改变父组件的状态
     *      子组件不能直接改变父组件的状态
     *      状态在哪个组件,更新状态的行为(方法)就应该定义在哪个组件
     *      解决:父组件定义函数,传递给子组件,子组件调用
     *
     *组件化编写功能的流程
     *      1、拆分组件
     *      2、实现静态组件(只有静态界面,没有动态数据和交互)
     *      3、实现动态组件
     *          1)实现初始化数据动态显示
     *          2) 实现交互功能
     */
        // 主界面
    class Counter extends React.Component {
        constructor(props) {
            super(props)
            // 初始化状态
            this.state = {
                todos: ['吃饭', '睡觉', '打豆豆']
            }
            this.addTodos = this.addTodos.bind(this)
        }

        // 定义一个添加的函数
        addTodos(todo) {
            // this.state.todos.unshift(todo)  //不能这么做
            const {todos} = this.state
            todos.unshift(todo)
            // 更新状态
            this.setState({todos})
        }

        render() {
            const {todos} = this.state
            return (
                <div>
                    <h1>Simple TODO List</h1>
                    <Add count={todos.length} addTodos={this.addTodos}/>
                    <List todos={todos}/>
                </div>
            )
        }
    }

    // 子界面
    class Add extends React.Component {
        constructor(prop) {
            super(prop)
            this.addData = this.addData.bind(this)
        }

        render() {
            return (
                <div>
                    <input type="text" ref={input => this.todoInput = input}/>
                    <button onClick={this.addData}>add # {this.props.count + 1} </button>
                </div>
            )
        }

        addData() {
            // 1、读取输入的数据
            const data = this.todoInput.value.trim();
            // 2、检查合法性
            if (!data) {
                return
            }
            // 3、添加
            console.log(data)
            this.props.addTodos(data)
            // 4、清除输入
            this.todoInput.value = ''
        }
    }

    // 数据校验,放在上面出错
    Add.propTypes = {
        count: PropTypes.number.isRequired,
        addTodos: PropTypes.func.isRequired
    }

    // 子界面
    class List extends React.Component {
        render() {
            const {todos} = this.props;
            /* => : 箭头函数的意义,有两个:函数、return, 这里如果加 {}:方法体 的话,里面一定要有 return*/
            /*todos.map((value, index)=><li key={index}>{value}</li>)*/
            return (
                <div>
                    <ul>
                        {todos.map((value, index) => {
                            return <li key={index}>{value}</li>
                        })}
                    </ul>
                </div>
            )
        }
    }

    List.propTypes = {
        todos: PropTypes.array.isRequired
    }
    ReactDOM.render(<Counter/>, document.getElementById('example'))
</script>
</body>

6.3 技术点(注意:数据在哪,操作方法就在哪)

  1. 设计三个组件,一个主页面Counter、一个添加页面Add、一个列表页面List
  2. state数据在主页面中,todos数组会传给List组件,todos长度、添加的方法addTodos()会传给Add组件。
  3. 注意,方法也可以作为数据传给子组件。通过this.props进行接收。
  4. 在Add组件中调用父组件的添加方法。
  5. 在List组件中通过this.props.todos 获取数据,然后在render()方法中进行遍历渲染出来。

6.4 React工具使用,查看三个属性

在Google中安装扩展软件,安装React扩展工具。可以查看自己定义的组件,以及三大属性,其实只能看到state和props,这两个是在组件上,ref是在标签上,这个只能在元素中查看。
看截图:
Counter类组件
在这里插入图片描述
Add类组件
在这里插入图片描述

6.5 功能界面的组件化编码流程(无比重要)

  1. 拆分组件: 拆分界面,抽取组件

  2. 实现静态组件: 使用组件实现静态页面效果

  3. 实现动态组件
    a. 动态显示初始化数据
    b. 交互功能(从绑定事件监听开始)

七、收集表单数据

7.1 需求描述

需求: 自定义包含表单的组件

  1. 输入用户名密码后, 点击登陆提示输入信息
  2. 不提交表单

7.2 理解

  1. 问题: 在react应用中, 如何收集表单输入数据

  2. 包含表单的组件分类
    a. 受控组件: 表单项输入数据能自动收集成状态
    b. 非受控组件: 需要时才手动读取表单输入框中的数据

7.3 代码实例

<body>
<div id="example"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
    /**
     * 需求: 自定义包含表单的组件
     *  1、界面如下所示
     *  2、输入用户名密码后,点击登陆提示输入信息
     *  3、不提交表单  event.preventDefault()
     */
    class LoginForm extends React.Component {
        constructor(prop) {
            super(prop)
            this.state = {
                pwd: ''
            }
            this.handleLogin = this.handleLogin.bind(this)
            this.handleChange = this.handleChange.bind(this)
        }
        render() {
            return (
                /**
                 * 用户名 为非受控组件
                 * 密码 为受控组件
                 */
                <form action="/test" onSubmit={this.handleLogin}>
                    用户名:<input type="text" ref={input => this.username = input}/>
                    密码: <input type="password" value={this.state.pwd} ref={input => this.password = input}
                               onChange={this.handleChange}/>
                    <input type="submit" value="登陆"/>
                </form>
            )
        }
        handleLogin(event) {
            const uname = this.username.value  // 操作DOM
            const {pwd} = this.state           // 操作react 属性
            alert(`准备提交的用户名为${uname}, 密码${pwd}`)
            // 阻止事件的默认行为(提交)
            event.preventDefault()
        }
        handleChange(event) {
            // 读取输入框的值
            const password = event.target.value
            // 更新pwd的状态
            this.setState({pwd: password})
        }
    }
    ReactDOM.render(<LoginForm/>, document.getElementById('example'))
</script>
</body>

页面:
在这里插入图片描述

7.4 步骤、技术点

步骤与前一致

  1. 这里需要理解**受控组件和非受控组件**。
  2. 受控组件:通过onChange()事件,将input值与state的值链接起来,进行统一。

八、组件生命周期

8.1 需求效果

需求: 自定义组件

  1. 让指定的文本做显示/隐藏的渐变动画
  2. 切换持续时间为2S
  3. 点击按钮从界面中移除组件界面

8.2 理解

  1. 组件对象从创建到死亡它会经历特定的生命周期阶段
  2. React组件对象包含一系列的勾子函数(生命周期回调函数), 在生命周期特定时刻回调
  3. 我们在定义组件时, 可以重写特定的生命周期回调函数, 做特定的工作

8.3 生命周期流程图

在这里插入图片描述

8.4 生命周期详述

  1. 组件的三个生命周期状态:
    • Mount:插入真实 DOM
    • Update:被重新渲染
    • Unmount:被移出真实 DOM
  2. React 为每个状态都提供了勾子(hook)函数
    • componentWillMount()(舍弃)
    • componentDidMount()
    • componentWillUpdate()
    • componentDidUpdate()
    • componentWillUnmount()
  3. 生命周期流程:
    a. 第一次初始化渲染显示: ReactDOM.render()
    • constructor(): 创建对象初始化state
    • componentWillMount() : 将要插入回调
    • render() : 用于插入虚拟DOM回调
    • componentDidMount() : 已经插入回调
      b. 每次更新state: this.setSate()
    • componentWillUpdate() : 将要更新回调
    • render() : 更新(重新渲染)
    • componentDidUpdate() : 已经更新回调
      c. 移除组件: ReactDOM.unmountComponentAtNode(containerDom)
    • componentWillUnmount() : 组件将要被移除回调

8.5 重要的勾子

  1. render(): 初始化渲染或更新渲染调用
  2. componentDidMount(): 开启监听, 发送ajax请求
  3. componentWillUnmount(): 做一些收尾工作, 如: 清理定时器
  4. componentWillReceiveProps(): 后面需要时讲

九、虚拟DOM与DOM Diff算法

9.1 代码实例

class HelloWorld extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
        date: new Date()
    }
  }

  componentDidMount () {
    setInterval(() => {
      this.setState({
          date: new Date()
      })
    }, 1000)
  }

  render () {
    console.log('render()')
    return (
      <p>
        Hello, <input type="text" placeholder="Your name here"/>!&nbsp;
        It is {this.state.date.toTimeString()}
      </p>
    )
  }
}

ReactDOM.render(
  <HelloWorld/>,
  document.getElementById('example')
)

9.2 基本原理图

在这里插入图片描述

十、react引用(基于react脚手架)

10.1 使用create-react-app创建react应用

10.1.1 react脚手架

  1. xxx脚手架: 用来帮助程序员快速创建一个基于xxx库的模板项目
    a. 包含了所有需要的配置
    b. 指定好了所有的依赖
    c. 可以直接安装/编译/运行一个简单效果

  2. react提供了一个用于创建react项目的脚手架库: create-react-app

  3. 项目的整体技术架构为: react + webpack + es6 + eslint

  4. 使用脚手架开发的项目的特点: 模块化, 组件化, 工程化

10.1.2 创建项目并启动

npm install -g create-react-app
create-react-app hello-react
cd hello-react
npm start

10.1.3 react脚手架项目结构

ReactNews
    |--node_modules---第三方依赖模块文件夹
    |--public
        |-- index.html-----------------主页面
    |--scripts
        |-- build.js-------------------build打包引用配置
    |-- start.js-------------------start运行引用配置
    |--src------------源码文件夹
        |--components-----------------react组件
        |--index.js-------------------应用入口js
    |--.gitignore------git版本管制忽略的配置
    |--package.json----应用包配置文件 
    |--README.md-------应用描述说明的readme文件

10.2 项目结构

在这里插入图片描述
项目入口 js index.js

10.2 demo:评论管理

效果:
在这里插入图片描述
拆分组件:
应用组件: App

  • state: comments/array
    添加评论组件: CommentAdd
  • state: username/string, content/string
  • props: add/func
    评论列表组件: CommentList
  • props: comment/object, delete/func, index/number
    评论项组件: CommentItem
  • props: comments/array, delete/func

实现静态组件

实现动态组件

1、 动态展示初始化数据

  • 初始化状态数据
  • 传递属性数据

2、 响应用户操作, 更新组件界面

  • 绑定事件监听, 并处理
  • 更新state

10.3 demo:评论管理

项目目录:
在这里插入图片描述

代码上库啦。

十一、react ajax

11.1 理解

11.1.1 前置说明

  1. React本身只关注于界面, 并不包含发送ajax请求的代码
  2. 前端应用需要通过ajax请求与后台进行交互(json数据)
  3. react应用中需要集成第三方ajax库(或自己封装)

11.1.2 常用的ajax请求库

  1. jQuery: 比较重, 如果需要另外引入不建议使用

  2. axios: 轻量级, 建议使用
    a. 封装XmlHttpRequest对象的ajax
    b. promise风格
    c. 可以用在浏览器端和node服务器端

  3. fetch: 原生函数, 但老版本浏览器不支持
    a. 不再使用XmlHttpRequest对象提交ajax请求
    b. 为了兼容低版本的浏览器, 可以引入兼容库fetch.js

11.1.3 效果

需求:

  1. 界面效果如下
  2. 根据指定的关键字在github上搜索匹配的最受关注的库
  3. 显示库名, 点击链接查看库
  4. 测试接口: https://api.github.com/search/repositories?q=r&sort=stars
    在这里插入图片描述
    在这里插入图片描述

11.1.4 代码实例

<body>
<div id="example"></div>
<script type="text/javascript" src="../js/react.development.js"></script>
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script>
<script type="text/babel">
    /**
     * 需求:
     * 1、界面效果如下,
     * 2、根据指定的关键字在GitHub上搜索匹配的最受关注的库
     * 3、显示库名,点击链接查看库
     * 4、测试接口:https://api.github.com/search/repositories?q=r&sort=stars
     */
    class MostStarRepo extends React.Component {
        state = {
            repoName: '',
            repoUrl: ''
        }
        // 最后发请求
        componentDidMount() {
            // 使用 axios 发送 异步的Ajax 请求  re:可以改变可以传  sort=stars:排序模式
            const url = 'https://api.github.com/search/repositories?q=re&sort=stars'
            axios.get(url)
                .then(response => {
                    const result = response.data
                    console.log(response);
                    // 得到数据
                    const {name, html_url} = result.items[0]
                    // 更新状态
                    this.setState({
                        repoName: name,
                        repoUrl: html_url
                    })
                })
                // 错误信息
                .catch(error => {
                    alert(error.message)
                })
            // 使用 fetch 发送异步的 Ajax 请求
            /*fetch(url)
                .then(response => {
                    return response.json()
                })
                .then(data => {
                    // 得到数据
                    const {name, html_url} = data.items[0]
                    // 更新状态
                    this.setState({
                        repoName: name,
                        repoUrl: html_url
                    })
                })*/
        }
        render() {
            const {repoName, repoUrl} = this.state
            if (!repoName) {
                return <h2>Loading</h2>
            } else {
                return <h2>Most star repo is <a href={repoUrl}>{repoName}</a></h2>
            }
        }
    }
    ReactDOM.render(<MostStarRepo/>, document.getElementById('example'))
</script>
</body>

11.2 axios

11.2.1 文档

https://github.com/axios/axios

11.2.1 相关API

1、 GET请求

axios.get('/user?ID=12345')
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

axios.get('/user', {
    params: {
      ID: 12345
    }
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

2、 POST请求

axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
})
.then(function (response) {
  console.log(response);
})
.catch(function (error) {
  console.log(error);
});

11.3 demo: github users

11.3.1 需求描述

在这里插入图片描述

11.3.2 拆分组件

App

  • state: searchName/string
    Search
  • props: setSearchName/func

List

  • props: searchName/string
  • state: firstView/bool, loading/bool, users/array, errMsg/string

11.3.3 代码实例

上库啦······ 库中代码为:13_react-app

  1. 编写静态组件
  2. 编写动态组件:componentWillReceiveProps(nextProps): 监视接收到新的props, 发送ajax
    使用axios库发送ajax请求

11.4 Fetch

11.4.1 文档

  1. https://github.github.io/fetch/
  2. https://segmentfault.com/a/1190000003810652

11.4.2 相关API

1、 GET请求

fetch(url).then(function(response) {
  return response.json()
}).then(function(data) {
  console.log(data)
}).catch(function(e) {
  console.log(e)
});

2、 POST请求

fetch(url, {
  method: "POST",
  body: JSON.stringify(data),
}).then(function(data) {
  console.log(data)
}).catch(function(e) {
  console.log(e)
})

十二、几个重要技术总结

12.1 组件间通信

12.1.1 方式一: 通过props传递

  1. 共同的数据放在父组件上, 特有的数据放在自己组件内部(state)
  2. 通过props可以传递一般数据和函数数据, 只能一层一层传递
  3. 一般数据–>父组件传递数据给子组件–>子组件读取数据
  4. 函数数据–>子组件传递数据给父组件–>子组件调用函数

12.1.2 方式二: 使用消息订阅(subscribe)-发布(publish)机制

  1. 工具库: PubSubJS
  2. 下载: npm install pubsub-js --save
  3. 使用:
    import PubSub from ‘pubsub-js’ //引入
    PubSub.subscribe(‘delete’, function(data){ }); //订阅
    PubSub.publish(‘delete’, data) //发布消息

12.1.3 方式三: redux

后面专门讲解

12.2 事件监听理解

12.2.1 原生DOM事件

  1. 绑定事件监听
    a. 事件名(类型): 只有有限的几个, 不能随便写
    b. 回调函数
  2. 触发事件
    a. 用户操作界面
    b. 事件名(类型)
    c. 数据()

12.2.2 自定义事件(消息机制)

  1. 绑定事件监听
    a. 事件名(类型): 任意
    b. 回调函数: 通过形参接收数据, 在函数体处理事件
  2. 触发事件(编码)
    a. 事件名(类型): 与绑定的事件监听的事件名一致
    b. 数据: 会自动传递给回调函数

12.3 ES6常用新语法

  1. 定义常量/变量: const/let
  2. 解构赋值: let {a, b} = this.props import {aa} from ‘xxx’
  3. 对象的简洁表达: {a, b}
  4. 箭头函数:
    a. 常用场景
    组件的自定义方法: xxx = () => {}
    参数匿名函数
    b. 优点:
    简洁
    没有自己的this,使用引用this查找的是外部this
  5. 扩展(三点)运算符: 拆解对象(const MyProps = {}, )
  6. 类: class/extends/constructor/super
  7. ES6模块化: export default | import

十三、react-router

13.1 项目理解

13.1.1 react-router的理解

  1. react的一个插件库
  2. 专门用来实现一个SPA应用
  3. 基于react的项目基本都会用到此库

13.1.2 SPA的理解

  1. 单页Web应用(single page web application,SPA)
  2. 整个应用只有一个完整的页面
  3. 点击页面中的链接不会刷新页面, 本身也不会向服务器发请求
  4. 当点击路由链接时, 只会做页面的局部更新
  5. 数据都需要通过ajax请求获取, 并在前端异步展现

13.1.3 路由的理解

  1. 什么是路由?
    a. 一个路由就是一个映射关系(key:value)
    b. key为路由路径, value可能是function/component

  2. 路由分类
    a. 后台路由: node服务器端路由, value是function, 用来处理客户端提交的请求并返回一个响应数据
    b. 前台路由: 浏览器端路由, value是component, 当请求的是路由path时, 浏览器端前没有发送http请求, 但界面会更新显示对应的组件

  3. 后台路由
    a. 注册路由: router.get(path, function(req, res))
    b. 当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据

  4. 前端路由
    a. 注册路由: < Route path="/about" component={About}>
    b. 当浏览器的hash变为#about时, 当前路由组件就会变为About组件

13.1.4 前端路由的实现

  1. history库
    a. 网址: https://github.com/ReactTraining/history
    b. 管理浏览器会话历史(history)的工具库
    c. 包装的是原生BOM中window.history和window.location.hash

  2. history API
    a. History.createBrowserHistory(): 得到封装window.history的管理对象
    b. History.createHashHistory(): 得到封装window.location.hash的管理对象
    c. history.push(): 添加一个新的历史记录
    d. history.replace(): 用一个新的历史记录替换当前的记录
    e. history.goBack(): 回退到上一个历史记录
    f. history.goForword(): 前进到下一个历史记录
    g. history.listen(function(location){}): 监视历史记录的变化

13.2 react-router相关API

13.2.1 react-router组件

<BrowserRouter>
<HashRouter>
<Route>
<Redirect>
<Link>
<NavLink>
<Switch>

13.2.2 其它

  1. history对象
  2. match对象
  3. withRouter函数

13.3 基本路由使用

13.3.1 效果

在这里插入图片描述

13.3.2 准备

  1. 下载react-router: npm install --save react-router@4
  2. 引入bootstrap.css: <link rel="stylesheet" href="/css/bootstrap.css">

13.4 嵌套路由使用

13.4.1 效果

在这里插入图片描述

13.5 向路由组件传递参数数据

13.5.1 效果

在这里插入图片描述

13.6 多种路由跳转方式(重要)

  1. 一种为标签方式跳转
  2. 一种为事件方式跳转:添加事件,需要借助history对象

原来没加router时,组件的属性有 props、state
加上route时,在Route下的组件上,有了history、location、match三个对象。

13.6.1 效果

在这里插入图片描述

13.6.2 代码实例

都上库啦。
代码为 14_react_router,三级路由都在这一个项目中。

十四、React UI

14.1 最流行的开源React UI组件库

14.1.1 material-ui(国外)

  1.  官网: http://www.material-ui.com/#/
    
  2.  github: https://github.com/callemall/material-ui
    

14.1.2 ant-design(国内蚂蚁金服)

  1.  PC官网: https://ant.design/index-cn
    
  2. 移动官网: https://mobile.ant.design/index-cn

  3.  Github: https://github.com/ant-design/ant-design/
    
  4. Github: https://github.com/ant-design/ant-design-mobile/

14.2 ant-design-mobile使用入门

14.2.1 效果

在这里插入图片描述

14.2.2 使用create-react-app创建react应用

npm install create-react-app -g
create-react-app antm-demo
cd antm-demo
npm start

14.2.3 搭建antd-mobile的基本开发环境

1、

     下载

npm install antd-mobile --save

2、 src/App.jsx

import React, {Component} from 'react'
// 分别引入需要使用的组件
import Button from 'antd-mobile/lib/button'
import Toast from 'antd-mobile/lib/toast'

export default class App extends Component {
  handleClick = () => {
    Toast.info('提交成功', 2)
  }

  render() {
    return (
      <div>
        <Button type="primary" onClick={this.handleClick}>提交</Button>
      </div>
    )
  }
}

3、

     src/index.js
import React from 'react';
import ReactDOM from 'react-dom'
import App from "./App"
// 引入整体css
import 'antd-mobile/dist/antd-mobile.css'


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

4、

     index.html
<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>

7.2.4. 实现按需打包(组件js/css)

1、 下载依赖包
yarn add react-app-rewired customize-cra babel-plugin-import --save

2、 修改默认配置:
package.json

"scripts": {
  "start": "react-app-rewired start",
  "build": "react-app-rewired build",
  "test": "react-app-rewired test --env=jsdom"
}

3、 config-overrides.js

const {injectBabelPlugin} = require('react-app-rewired');
module.exports = function override(config, env) {
  config = injectBabelPlugin(['import', {libraryName: 'antd-mobile', style: 'css'}], config);
  return config;
};

4、 编码

// import 'antd-mobile/dist/antd-mobile.css'

// import Button from 'antd-mobile/lib/button'
// import Toast from 'antd-mobile/lib/toast'
import {Button, Toast} from 'antd-mobile'

扩展,数组方法

1. map()

遍历数组

/**
* 功能:动态展示列表数据
*
* 问题:如何将一个数据的数组 转换为 一个标签的数组   很常用
*      使用数组的map() 方法 和 箭头函数
* */
const names = ['jQuery', 'zepto', 'angular', 'react', 'vue']
 // 1、创建虚拟DOM
 // li 标签一定要带 key属性,而且还不能一样 否则警告
 const ul = (
     <ul>
         {names.map(name=> <li key={name}>{name}</li>)}
     </ul>
 )

2. unshift()

在数组的头部添加新值

3. splice()

splice(value, 1):删除
splice(value, 0, value2):替换
splice(value): 添加

4. filter()

过滤数组,将下标不等于0的过滤掉,返回一个新的数组。

const comments = [
    {username: 'Tom', content: 'React 挺好的!'},
    {username: 'Jack', content: 'React 挺简单的!'}
];

state.filter((comment, index) => {
    return (index !== 0)
});
相关文章
|
3月前
|
前端开发
React | 修改React脚手架的默认端口号?
React | 修改React脚手架的默认端口号?
152 64
|
1月前
|
前端开发 JavaScript
手敲Webpack 5:React + TypeScript项目脚手架搭建实践
手敲Webpack 5:React + TypeScript项目脚手架搭建实践
|
2月前
|
移动开发 小程序 数据可视化
基于npm CLI脚手架的uniapp项目创建、运行与打包全攻略(微信小程序、H5、APP全覆盖)
基于npm CLI脚手架的uniapp项目创建、运行与打包全攻略(微信小程序、H5、APP全覆盖)
263 3
|
3月前
|
前端开发 NoSQL MongoDB
React技术栈-基于react脚手架编写评论管理案例
这篇文章介绍了在MongoDB中使用sort和投影来对查询结果进行排序和限制返回的字段,通过具体的命令示例展示了如何实现这些操作。
53 6
React技术栈-基于react脚手架编写评论管理案例
|
3月前
|
XML 移动开发 前端开发
使用duxapp开发 React Native App 事半功倍
对于Taro的壳子,或者原生React Native,都会存在 `android` `ios`这两个文件夹,而在duxapp中,这些文件夹的内容是自动生成的,那么对于需要在这些文件夹中修改的配置内容,例如包名、版本号、新架构开关等,都通过配置文件的方式配置了,而不需要需修改具体的文件
|
3月前
|
前端开发 JavaScript
React技术栈-react的脚手架创建应用案例
本文介绍了如何使用React的官方脚手架工具create-react-app快速创建React项目,并展示了项目的目录结构和基本的代码文件,以及如何启动和运行React应用。
36 2
|
4月前
|
前端开发 JavaScript 中间件
React脚手架create-react-app简介
【8月更文挑战第13天】React脚手架create-react-app简介
237 4
|
前端开发 Java Android开发
|
2月前
|
JSON 小程序 JavaScript
uni-app开发微信小程序的报错[渲染层错误]排查及解决
uni-app开发微信小程序的报错[渲染层错误]排查及解决
563 7
|
2月前
|
小程序 JavaScript 前端开发
uni-app开发微信小程序:四大解决方案,轻松应对主包与vendor.js过大打包难题
uni-app开发微信小程序:四大解决方案,轻松应对主包与vendor.js过大打包难题
686 1