react入门笔记2

1. 在项目中使用 react

  1. 运行 cnpm i react react-dom -S 安装包

    • react: 专门用于创建组件和虚拟DOM的,同时组件的生命周期都在这个包中
    • react-dom: 专门进行DOM操作的,最主要的应用场景,就是ReactDOM.render()
  2. index.html页面中,创建容器:

    <!-- 容器,将来,使用 React 创建的虚拟DOM元素,都会被渲染到这个指定的容器中 -->
    <div id="app"></div>
    
  3. js文件中导入包:

    import React from 'react'
    import ReactDOM from 'react-dom'
    
  4. 创建虚拟DOM元素:

    // 这是 创建虚拟DOM元素的 API    <h1 title="啊,五环" id="myh1">你比四环多一环</h1>
    //  第一个参数: 字符串类型的参数,表示要创建的标签的名称
    //  第二个参数:对象类型的参数, 表示创建的元素的属性节点,可以用null
    //  第三个参数: 子节点
    const myh1 = React.createElement('h1', { title: '啊,五环', id: 'myh1' }, '你比四环多一环')
    
  5. 渲染:

    // 3. 渲染虚拟DOM元素
    // 参数1: 表示要渲染的虚拟DOM对象
    // 参数2: 指定容器,注意:这里不能直接放 容器元素的Id字符串,需要放一个容器的DOM对象
    ReactDOM.render(myh1, document.getElementById('app'))
    

2. JSX语法

什么是JSX语法:就是符合 xml 规范的 JS 语法;(语法格式相对来说,要比HTML严谨很多)

  1. 如何启用 jsx 语法?

    • 安装 babel 插件

      • 运行cnpm i babel-core babel-loader babel-plugin-transform-runtime -D
      • 运行cnpm i babel-preset-env babel-preset-stage-0 -D
    • 安装能够识别转换jsx语法的包 babel-preset-react

      • 运行cnpm i babel-preset-react -D
    • 添加 .babelrc 配置文件

      {
        "presets": ["env", "stage-0", "react"],
        "plugins": ["transform-runtime"]
      }
      
    • 添加babel-loader配置项:

      module: { //要打包的第三方模块
          rules: [
            { test: /\.js|jsx$/, use: 'babel-loader', exclude: /node_modules/ }
          ]
      }
      

  2. jsx 语法的本质: 并不是直接把 jsx 渲染到页面上,而是内部先转换成了 createElement 形式,再渲染的;

  3. 在 jsx 中混合写入 js 表达式:在 jsx 语法中,要把 JS代码写到 { }

    • 渲染数字
      let a = 10;
      
      ReactDOM.render(<div>{a}</div>, document.getElementById('app')) 
      
    • 渲染字符串
      let a = 'aaa';
       
      ReactDOM.render(<div>{a}</div>, document.getElementById('app')) 
      
    • 渲染布尔值
      let a = false;
      
      ReactDOM.render(<div>{a ? '条件为真' : '条件为假'}</div>,document.getElementById('app'))
      
    • 为属性绑定值
      let title = "sss";
      
      ReactDOM.render(<div title={title}></div>, document.getElementById('app')) 
      
    • 渲染jsx元素
      let aaa = <h1>111</h1>;\
      
      ReactDOM.render(<div>{aaa}</div>, document.getElementById('app')) 
      
    • 渲染jsx元素数组
      let arr = [
      	<h1>111</h1>,
      	<h2>222</h2>
      ];
      
      ReactDOM.render(<div>{arr}</div>, document.getElementById('app')) 
      
    • 将普通字符串数组,转为jsx数组并渲染到页面上【两种方案】
      第一种
      const arrStr = ['aaa','bbb','ccc']
      const nameArr = []
      arrStr.forEach(item => {
      	const temp = <h1>{item}</h1>
      	nameArr.push(temp)
      })
      
      ReactDOM.render(<div>{nameArr}</div>, document.getElementById('app'))
      
      第二种
      const arrStr = ['aaa','bbb','ccc']
      
      ReactDOM.render(<div>
      {arrStr.map(item => <h1>{item}</h1>)}
      </div>, document.getElementById('app'))
      
  4. 在 jsx 中 写注释:推荐使用{ /* 这是注释 */ }

  5. 为 jsx 中的元素添加class类名:需要使用className 来替代 classhtmlFor替换label的for属性

  6. 在JSX创建DOM的时候,所有的节点,必须有唯一的根元素进行包裹,如果不想多一个没用的根元素包裹,可以用react提供的占位符Fragment,Fragment不会渲染到html结构中

    import React, { Component , Fragment} from 'react'
    
    class TodoList extends Component{
        render() {
            return (
                <Fragment>
                    <input /><button>提交</button>
                    <ul>
                        <li>react</li>
                        <li>vue</li>
                    </ul>
                </Fragment>
            )
        }
    }
    
    export default TodoList
    
  7. 在 jsx 语法中,标签必须 成对出现,如果是单标签,则必须自闭和

当 编译引擎,在编译JSX代码的时候,如果遇到了<那么就把它当作 HTML代码去编译,如果遇到了 {} 就把 花括号内部的代码当作 普通JS代码去编译;

3. React中创建组件

第1种 - 创建组件的方式

使用构造函数来创建组件,如果要接收外界传递的数据,需要在 构造函数的参数列表中使用props来接收;

必须要向外return一个合法的JSX创建的虚拟DOM;

  • 创建组件:

    function Hello () { 
    	// return null 
    	return <div>Hello 组件</div>
    }
    
  • 为组件传递数据:

    const dog = {
    	name : "大黄",
    	age : 3
    }
    // 在构造函数中,使用 props 形参,接收外界 传递过来的数据
    function Hello(props) {
    	// props.name = 'zs'
    	console.log(props)
    // 结论:不论是 Vue 还是 React,组件中的 props 永远都是只读的;不能被重新赋值;
    	return <div>这是 Hello 组件 --- {props.name} --- {props.age}</div>
    }
    // 使用组件并 为组件传递 props 数据
    ReactDOM.render(<div>
    	<Hello name={dog.name} age={dog.age}></Hello>
    	//es6写法
    	//<Hello {...dog}></Hello>
    </div>, document.getElementById('app')) 
    
  1. 父组件向子组件传递数据

  2. 使用{…obj}属性扩散传递数据

  3. 将组件封装到单独的文件中

  4. 注意:组件的名称首字母必须是大写

  5. 在导入组件的时候,如何省略组件的.jsx后缀名:

    // 打开 webpack.config.js ,并在导出的配置对象中,新增 如下节点:
    resolve: {
        extensions: ['.js', '.jsx', '.json'], // 表示,这几个文件的后缀名,可以省略不写
        alias: {
            '@': path.join(__dirname, './src')// 这样@就表示项目根目录中src这一层目录
        }
    }
    
  6. 在导入组件的时候,配置和使用@路径符号

第2种 - 创建组件的方式

使用 class 关键字来创建组件

ES6 中 class 关键字,是实现面向对象编程的新形式;

了解ES6中 class 关键字的使用

  1. class 中 constructor 的基本使用

  2. 实例属性和实例方法

  3. 静态属性和静态方法

    // 创建了一个动物类
    // 注意:在 class 的 { } 区间内,只能写 构造器、静态方法和静态属性、实例方法
    class Animal {
      // 这是类中的 构造器
      // 每一个类中,都有一个构造器,如果我们程序员没有手动指定构造器,那么,可以认为类内部有个隐形的、看不见的 空构造器,类似于 constructor(){}
      // 构造器的作用,就是,每当 new 这个类的时候,必然会优先执行 构造器中的代码
      constructor(name, age) {
        // 实例属性
        this.name = name;
        this.age = age
      }	
      // 在 class 内部,通过 static 修饰的属性,就是静态属性
      static info = "eee" // (用的不多)
      // 这是动物的实例方法(会经常用到 实例方法)
      jiao() {
        console.log('动物的实例方法')
      }
      // 这是 动物 类的静态方法(用的不多)
      static show() {
        console.log('这是 Animal 的静态 show 方法')
      }
    }
    
    const a1 = new Animal('大黄', 3);
    console.log(a1);
    a1.jiao();
    Animal.show();
    
  4. 使用 extends 关键字实现继承

    // 这是父类 【可以直接把 父类,理解成 原型对象 prototype】
    class Person {
    	constructor(name, age){
        	this.name = name
        	this.age = age
    	}
      	//打招呼 的 实例方法
    	sayHello(){
        	console.log('大家好')
      	}
    }
    
    
    // 这是子类 美国人 
    // 在 class 类中,可以使用 extends 关键字,实现 子类继承父类
    // 语法:class 子类 extends 父类 {}
    class American extends Person {
    	constructor(name, age){
        // 问题1:为什么一定要在 constructor 中调用 super
        // 答案: 因为,如果一个子类,通过 extends 关键字继承了父类,那么,在子类的 constructor 构造函数中,必须 优先调用一下 super(),规定
        // 问题2:super 是个什么东西?
        // 答案: super 是一个函数,而且,它是 父类的 构造器;子类中的 super,其实就是父类中,constructor 构造器的一个引用;
        	super(name, age)
        }
    }
    
    const a1 = new American('Jack', 20)
    console.log(a1)
    a1.sayHello()
    
    // 这是子类 中国人
    class Chinese extends Person{
      // IDNumber 身份证号 【中国人独有的】,既然是独有的,就不适合 挂载到 父类上;
    	constructor(name, age, IDNumber){
        	super(name, age)
        	// 语法规范:在子类中, this 只能放到 super 之后使用
        	this.IDNumber = IDNumber
      	}
    }
    
    const c1 = new Chinese('张三', 22, '130428******')
    console.log(c1)
    c1.sayHello()
    

基于class关键字创建组件

  1. 最基本的组件结构:

    // 如果要使用 class 定义组件,必须 让自己的组件,继承自 React.Component
    class 组件名称 extends React.Component {
        // 在 组件内部,必须有 render 函数,作用:渲染当前组件对应的 虚拟DOM结构
        render(){
            // render 函数中,必须 返回合法的 JSX 虚拟DOM结构
            return <div>这是 class 创建的组件</div>
        }
    }
    
  2. 组件的props和state

    // import React, {Component} from 'react'
    import React from 'react'
    import ReactDOM from 'react-dom'
    
    // class 关键字创建组件
    class Movie extends React.Component {
      constructor() {
        // 由于 Movie 组件,继承了 React.Component 这个父类,所以,自定义的构造器中,必须 调用 super()
        super()
        // 只有调用了 super() 以后,才能使用 this 关键字
        this.state = { 
          msg: '大家好,我是 class 创建的 Movie组件'
        }
      }
    
      // render 函数的作用,是 渲染 当前组件所对应的 虚拟DOM元素
      render() {
        // 在 class 关键字创建的组件中,如果想使用 外界传递过来的 props 参数,不需接收,直接通过 this.props.*** 访问即可	
        // 注意:不论是 class 还是普通 function 创建的组件,它们的 props 都是只读的;	
        // 在 class 创建的组件中, this.state 上的数据,都是可读可写的!
        // this.state.msg = 'msg的值被我修改了!'
    
        return <div>
          {/* 注意:在 class 组件内部,this 表示 当前组件的实例对象 */}
          这是 Movie 组件 -- {this.props.name} -- {this.props.age} -- {this.props.gender}
          <h3>{this.state.msg}</h3>
        </div>
      }
    }
    
    
    const user = {
      name: 'zs',
      age: 22,
      gender: '男'
    }
    
    // 3. 调用 render 函数渲染
    ReactDOM.render(<div>
      {/* 这里的 Movie 标签,其实,就是 Movie 类的一个实例对象 */}
      {/* <Movie name={user.name} age={user.age}></Movie> */}
      <Movie {...user}></Movie>
    </div>, document.getElementById('app'))
    

4. 两种创建组件方式的对比

注意:使用 class 关键字创建的组件,有自己的私有数据(this.state) 和 生命周期函数;

注意:使用 function 创建的组件,只有props,没有自己的私有数据和 生命周期函数;

  1. 构造函数创建出来的组件:叫做“无状态组件”【无状态组件今后用的不多】
  2. class关键字创建出来的组件:叫做“有状态组件”【今后用的最多】
  3. 什么情况下使用有状态组件?什么情况下使用无状态组件?
    • 如果一个组件需要有自己的私有数据,则推荐使用:class创建的有状态组件;
    • 如果一个组件不需要有私有的数据,则推荐使用:无状态组件;
    • React官方说:无状态组件,由于没有自己的state和生命周期函数,所以运行效率会比 有状态组件稍微高一些;

有状态组件和无状态组件之间的本质区别就是:有无state属性、和 有无生命周期函数;

  1. 组件中的 propsstate/data 之间的区别
    • props 中的数据都是外界传递过来的;
    • state/data 中的数据,都是组件私有的;(通过 Ajax 获取回来的数据,一般都是私有数据);
    • props 中的数据都是只读的;不能重新赋值;
    • state/data 中的数据,都是可读可写的;

猜你喜欢

转载自blog.csdn.net/weixin_36302575/article/details/86506309