React学习

React学习

一、React入门

React介绍
  1. 官网
  2. 介绍描述
    • 用于动态构建用户界面的Javascript库(只关注于视图)
    • 由Facebook开源
  3. React的特点
    • 声明式编码
    • 组件化编码
    • ReactNative 编写原生应用
    • 高效(优秀的 Diffing算法)
  4. React高效的原因
    • 使用虚拟(virtual)DOM,不总是直接操作页面真实DOM。
    • DOM diffing算法,最小化页面重绘
React的基本使用
  1. 相关js库

    • react.js:React核心库
    • React-dom.js:提供操作DOM的react扩展库
    • babel.min.js:解析JSX语法代码,转化为JS代码的库
  2. 创建虚拟DOM的两种方式

    • JSX语法

      <!DOCTYPE html>
      <html>
      <head>
          <meta charset="utf-8">
          <title>helloReact</title>
      </head>
      <body>
          <!-- 容器 -->
          <div id="app"></div>
          <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
          <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
          <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
      
          <script type="text/babel">
              //创建虚拟Dom
              const VDom = <h1 id="hello">Hello,React</h1>;
              //渲染虚拟Dom到页面
              ReactDOM.render(VDom,document.getElementById('app'))
              console.log(VDom)
          </script>
      </body>
      </html>
      
    • js方式(一般不用)

      <!DOCTYPE html>
      <html>
      <head>
          <meta charset="utf-8">
          <title>helloReact</title>
      </head>
      <body>
          <!-- 容器 -->
          <div id="app"></div>
          <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
          <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
      
          <script>
              //创建虚拟Dom
              const VDom = React.createElement('h1',{id:'title'},'Hello,React')
              //渲染虚拟Dom到页面
              ReactDOM.render(VDom,document.getElementById('app'))
              console.log(VDom)
          </script>
      </body>
      </html>
      
React JSX
  1. 全程是:Javascript XML

  2. react定义的一种类似于XML的JS扩展语法:js+XML

  3. 本质是 React.createElement(component,props,...children)方法的语法糖

  4. 作用:用来简化创建虚拟DOM

    • 写法:const VDom = <h1>Hello,React</h1>
    • 注意点1:它不是字符串,也不是HTM/XML标签
    • 注意点2:它最终产生的就是一个JS对象
  5. 标签名任意:HTML标签或其他标签

  6. jsx语法规则

    • 定义虚拟dom时,不要写引号

    • 标签中混入js表达式时,要用{}

    • 样式类名指定不要用class,要用className

    • 内联样式,要用 style={{key:value}}的形式去写,并且需要用小驼峰方式

    • 只有一个根标签

    • 标签必须闭合

    • 标签首字母

      • 若小写字母开头,则会将标签转为html同名元素,若html中无该标签对应的同名元素,则报错
      • 若大写字母开头,react会渲染对应的组件,若组件没有定义,则报错
      <!DOCTYPE html>
      <html>
      <head>
          <meta charset="utf-8">
          <title>helloReact</title>
          <style>
              .title{
                  color:orange;
              }
          </style>
      </head>
      <body>
          <!-- 容器 -->
          <div id="app"></div>
          <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
          <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
          <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
      
          <script type="text/babel">
              //创建虚拟Dom
              const VDom = (
                  <div>
                      <h1 className="title" style={{background:'red',fontSize:'30px'}}>
                          <span>Hello,React</span>
                      </h1>
                      <good>123</good>
                  </div>
              )
              //渲染虚拟Dom到页面
              ReactDOM.render(VDom,document.getElementById('app'))
              console.log(VDom)
          </script>
      </body>
      </html>
      
模块与组件、模块化与组件化的理解
模块
  1. 理解:向外提供特定功能的js程序,一般就是一个js文件
  2. 为什么要拆成模块:随着业务逻辑增加,代码越来越复杂
  3. 作用:复用js、简化js的编写、提高js运行效率
组件
  1. 理解:用来实现局部功能效果的代码和资源的集合(html/css/js/image 等等)
  2. 作用:复用编码,简化项目编码,提高运行效率
模块化

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

组件化

当应用是以多组件的方式实现,这个应用就是一个组件化的应用

二、React面向组件编程

基本理解和使用
  1. 函数式组件

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>helloReact</title>
    </head>
    <body>
        <!-- 容器 -->
        <div id="app"></div>
        <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
        <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
        <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    
        <script type="text/babel">
            //创建函数式组件
            function MyComponent(){
                return <h2>函数式组件</h2>
            }
            //渲染组件到页面
            ReactDOM.render(<MyComponent />,document.getElementById('app'))
        </script>
    </body>
    </html>
    
  2. 类式组件

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>helloReact</title>
    </head>
    <body>
        <!-- 容器 -->
        <div id="app"></div>
        <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
        <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
        <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    
        <script type="text/babel">
            //创建类式组件
            class MyComponent extends React.Component{
                render(){
                    return (
                        <div>
                            我是类式组件
                        </div>
                    )
                }
            }
            //渲染组件到页面
            ReactDOM.render(<MyComponent />,document.getElementById('app'))
        </script>
    </body>
    </html>
    
组件三大核心属性
state
  • 理解
    • state是组件对象最重要的属性,值是对象(可以包含多个 key--value组合)
    • 组件被称为“状态机”,通过更新组件的state来更新对应页面显示(重新渲染组件)
  • 强烈注意
    • 组件中render方法中的this为组件实例对象
    • 组件中自定义方法中this 为undefined,如何解决
    • 箭头函数
    • 状态数据,不能直接修改或更新 (setState)
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>helloReact</title>
    </head>
    <body>
        <!-- 容器 -->
        <div id="app"></div>
        <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
        <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
        <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

        <script type="text/babel">
            //创建类式组件
            class MyComponent extends React.Component{
                state = {count:0}
                //自定义方法——要用赋值语句的形式+箭头函数
                changeNum = ()=>{
                    const {count} = this.state
                    //注意:状态(state) 不可直接更改
                    //this.state.count = count++ //错误的写法
                    //状态必须通过setState 修改
                    this.setState({count:count+1})
                }
                render(){
                    const {count} = this.state
                    console.log('render')
                    return (
                        <div onClick={this.changeNum}>
                            点我加1-----{count}
                        </div>
                    )
                }
            }
            //渲染组件到页面
            ReactDOM.render(<MyComponent />,document.getElementById('app'))
        </script>
    </body>
</html>
props
  • 理解

    • 每个组件对象都会有props属性
    • 组件标签的所有属性都保存在props中
  • 作用

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

    • 扩展属性 <Person {...person} /> 用 ...运算符把对象上的所有属性传递到props上

    • 默认属性值

    Person.defaultProps = {
        age:18,
        sxe:'男'
    }
    • props类型限制

    使用 prop-types 库进行限制

    Person.propTypes = {
        name:PropTypes.string.isRequire,
        age:PropTypes.number
    }
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>helloReact</title>
        <style>
            .userItem{
                margin-bottom: 20px;
                border-bottom: 1px solid #cccccc;
            }
        </style>
    </head>
    <body>
        <!-- 容器 -->
        <div id="app"></div>
        <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
        <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
        <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

        <script type="text/babel">
            //创建组件
            class Person extends React.Component {
                state = {
                    userList:[
                        {id:1,name:'张三',age:20,sex:'男'},
                        {id:2,name:'李四',age:21,sex:'男'},
                        {id:3,name:'小红',age:22,sex:'女'},
                    ]
                }
                render(){
                    const {userList} = this.state
                    return (
                        <div>
                            <h3>用户列表</h3>
                            {
                                userList.map(item=>{
                                    return <UserItem {...item} key={item.id}></UserItem>
                                })
                            }

                        </div>
                    )
                }
            }
            class UserItem extends React.Component {
                render(){
                    const {name,age,sex} = this.props
                    return (
                        <ul className="userItem">
                            <li>姓名:{name}</li>
                            <li>性别:{sex}</li>
                            <li>年龄:{age}</li>
                        </ul>
                    )
                }
            }
            //渲染组件到页面
            ReactDOM.render(<Person />,document.getElementById('app'))
        </script>
    </body>
</html>
refs与事件绑定
  • 理解

    • 组件内的标签可以定义ref属性来标识自己
  • 使用

    • 字符串形式的ref (不推荐使用)
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>helloReact</title>
            <style>
                .userItem{
                    margin-bottom: 20px;
                    border-bottom: 1px solid #cccccc;
                }
            </style>
        </head>
        <body>
            <!-- 容器 -->
            <div id="app"></div>
            <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
            <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
            <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    
            <script type="text/babel">
                class Demo extends React.Component {
                    //展示左侧输入框的值
                    showData = ()=>{
                        this.refs.input1.value = '2222'
                    }
                    //显示右侧输入框的数据
                    showData2 = ()=>{
                        console.log(this.refs.input2.value)
                    }
                    render(){
                        return (
                            <div>
                                <input ref="input1" type="text" placeholder="点击按钮提示数据" />&nbsp;
                                <button onClick={this.showData}>提示</button>&nbsp;
                                <input ref="input2" onBlur={this.showData2} type="text" placeholder="失去焦点提示数据" />
                            </div>
                        )
                    }
                }
    
                ReactDOM.render(<Demo />,document.getElementById('app'))
            </script>
        </body>
    </html>
    
    • 回调形式的ref
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>helloReact</title>
            <style>
                .userItem{
                    margin-bottom: 20px;
                    border-bottom: 1px solid #cccccc;
                }
            </style>
        </head>
        <body>
            <!-- 容器 -->
            <div id="app"></div>
            <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
            <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
            <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    
            <script type="text/babel">
                class Demo extends React.Component {
                    state = {
                        value1:''
                    }
                    getInput1 = ()=>{
                        this.setState({value1:this.input1.value})
                    }
                    saveInput2 = (c)=>{
                        console.log(c)
                        this.input2 = c
                    }
                    render(){
                        const {value1} = this.state
                        return (
                            <div>
                                <input ref={c=> {this.input1 = c;console.log(c)}} type="text" placeholder="点击按钮提示数据" />&nbsp;
                                <button onClick={this.getInput1}>提示</button>&nbsp;
                                <input ref={this.saveInput2}  type="text" placeholder="失去焦点提示数据" />
                                <p>{value1}</p>
                            </div>
                        )
                    }
                }
    
                ReactDOM.render(<Demo />,document.getElementById('app'))
            </script>
        </body>
    </html>
    
    • createRef
    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="utf-8">
            <title>helloReact</title>
            <style>
                .userItem{
                    margin-bottom: 20px;
                    border-bottom: 1px solid #cccccc;
                }
            </style>
        </head>
        <body>
            <!-- 容器 -->
            <div id="app"></div>
            <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
            <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
            <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
    
            <script type="text/babel">
                class Demo extends React.Component {
                    /*
                    *  React.createRef 调用之后可以返回一个容器,该容器可以存储被ref所标识的节点
                    * 注意:该容器是“专人专用”
                    */
                    input1 = React.createRef()
                    getInput1 = ()=>{
                        console.log(this.input1.current.value)
                    }
                    render(){
                        return (
                            <div>
                                <input ref={this.input1} type="text" placeholder="点击按钮提示数据" />&nbsp;
                                <button onClick={this.getInput1}>提示</button>&nbsp;
                                <input type="text" placeholder="失去焦点提示数据" />
                            </div>
                        )
                    }
                }
    
                ReactDOM.render(<Demo />,document.getElementById('app'))
            </script>
        </body>
    </html>
    
  • 事件处理

    通过 onXXX属性指定事件处理函数(注意大小写)

    • React使用的是自定义(合成)事件,而不是使用原生DOM事件 ---- 兼容性
    • React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) --- 高效

    通过event.target得到发生事件的DOM元素对象 ----- 不要过渡使用ref

收集表单数据
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>helloReact</title>
        <style>
            .userItem{
                margin-bottom: 20px;
                border-bottom: 1px solid #cccccc;
            }
        </style>
    </head>
    <body>
        <!-- 容器 -->
        <div id="app"></div>
        <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
        <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
        <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

        <script type="text/babel">
            class Login extends React.Component {
                //初始化状态
                state = {
                    username:'',
                    password:'',
                }
                handleSub = (e)=>{
                    e.preventDefault()
                }
                //保存用户名
                saveUserName = (e)=>{
                    this.setState({username:e.target.value})
                }
                //保存密码
                savePassword = (e)=>{
                    this.setState({password:e.target.value})
                }
                render(){
                    return (
                        <form onSubmit={this.handleSub}>
                            用户名:<input onChange={this.saveUserName} type="text" name="username" />
                            密码:<input onChange={this.savePassword} type="password" name="password" />
                            <button>登陆</button>
                        </form>
                    )
                }
            }

            ReactDOM.render(<Login />,document.getElementById('app'))
        </script>
    </body>
</html>
组件生命周期
理解
  • 组件对象从创建到销毁它会经历特定的阶段
  • React组件对象包含了一系列钩子函数(生命周期回调函数),在特定的时刻调用
  • 我们在定义组件时,在特定的生命周期回调函数中做特定的工作
生命周期的三个阶段(旧版)
  1. 初始化阶段

    • constructor
    • componentWillMount
    • render
    • componentDidMount
  2. 更新阶段:由组件内部 this.setState()或者父组件render触发
    • shouldComponentUpdate
    • componentWillUpdate
    • render
    • componentDidUpdate
  3. 卸载组件
    • componentWillUnmout
生命周期的三个阶段(新版)
  1. 初始化阶段
    • constructor
    • getDerivedStateFromProps
    • render
    • componentDidMount
  2. 更新阶段:由组件内部 this.setState()或者父组件render触发
    • getDerivedStateFromProps
    • shouldComponentUpdate
    • render
    • getSnapshotBeforeUpdate(prevProps,prevState) 获取更新前快照,返回值传给 componentDidUpdate
    • componentDidUpdate(prevProps, prevState, snapshot) snapshot 为 getSnapshotBeforeUpdate 的返回值
  3. 卸载组件
    • componentWillUnmout

src=http___www.pianshen.com_images_809_84bca820ca779418cac9e1910c846f21.png&refer=http___www.pianshen

重要的钩子
  1. render:初始化渲染或更新渲染调用
  2. componentDidMount:组件挂载完毕
  3. componentWillUnmout:组件将要卸载,做一些收尾工作(例如:清除定时器)
即将废弃的钩子
  1. componentWillMount
  2. componentWillReceiveProps
  3. componentWillUpdate

不建议使用