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

简介: 这篇文章是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)
});
相关文章
|
2天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1517 4
|
29天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
5天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
492 19
|
2天前
|
存储 SQL 关系型数据库
彻底搞懂InnoDB的MVCC多版本并发控制
本文详细介绍了InnoDB存储引擎中的两种并发控制方法:MVCC(多版本并发控制)和LBCC(基于锁的并发控制)。MVCC通过记录版本信息和使用快照读取机制,实现了高并发下的读写操作,而LBCC则通过加锁机制控制并发访问。文章深入探讨了MVCC的工作原理,包括插入、删除、修改流程及查询过程中的快照读取机制。通过多个案例演示了不同隔离级别下MVCC的具体表现,并解释了事务ID的分配和管理方式。最后,对比了四种隔离级别的性能特点,帮助读者理解如何根据具体需求选择合适的隔离级别以优化数据库性能。
179 1
|
8天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
21天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
9天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
448 5
|
7天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
314 2
|
23天前
|
人工智能 IDE 程序员
期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟
在云栖大会上,阿里云云原生应用平台负责人丁宇宣布,「通义灵码」完成全面升级,并正式发布 AI 程序员。
|
25天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2608 22
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析