react 入门看这个就够了

1. React

1.1. 常识

React 是什么:用于构件用户界面的 JavaScript 库(将数据渲染为 HTML 视图,它不关注获取数据啥的,只给你渲染到 HTML 上面)

为什么要学:

  • 原生 JavaScript 操作 DOM (jQuery 也是操作 DOM,只是写起来简单) 繁琐、效率低(比如 document.getElementById() 一句话就是:DOM-API 操作 UI
  • 直接操作 DOM,浏览器会进行大量的重新绘制、重新排列,造成效率低下
  • 原生 JavaScript 没有组件化编码方案,代码复用率低

React 优点:

  • 采用组件化模式、声明式编码(命令式和声明式就像手动挡与自动挡的区别,命令式的步骤不能缺少,才能完成一个任务;而声明式可以自动帮你完成)
  • 在 React Native 中可以使用 React 语法进行移动端开发(利用 JavaScript 开发 app)
  • 使用虚拟 DOM + Diffing 算法,尽可能地减少了与真实 DOM 交互
    在这里插入图片描述

1.2. 旧版本使用

1.2.1. 库简介

  • babel.js

    • 之前的作用有:es6 转 es5 语法,让浏览器能够识别;模块化的时候 -> import 也需要靠它进行工作
    • 现在的新的一个作用:将 jsx 转为 js
  • react.development.js

    • react 的核心库
  • react-dom.development.js

    • react 用于操作 DOM 的核心库

1.2.2. 编写 hello-world


<body>
<!-- 1.准备好容器 -->
<div id="root"></div>
<!-- 2.引入核心库 -->
<script src="js/react.development.js"></script> <!-- 必须要先引入 react 核心库 -->
<script src="js/react-dom.development.js"></script>
<script src="js/babel.min.js"></script>
<!-- 必须写成 babel,意思是里面的代码是 jsx,需要用 babel 来转换 -->
<script type="text/babel">
	// 3.创建虚拟 DOM
    const VDOM = <h1>Hello React</h1> // 这里不是字符串,这就是个虚拟 DOM
    // 4.渲染虚拟 DOM 到 HTML 上
    ReactDOM.render(VDOM, document.getElementById('root'))  // 引入 react 就会在 window 添加一个 React 成员;引入 react-dom 就会在 window 添加一个 ReactDOM 成员
    console.log(window)
</script>
</body>

在这里插入图片描述

1.2.3. 为什么要用 jsx

需求:生成 <div id="root"><span>Hello React</span></div> 这样一个节点

原生 JavaScript:

// createElement 是创建真实 DOM
React.createElement('div', {
    id: 'root' }, React.createElement('span', {
   }, 'Hello World'))

jsx:

const VDOM = (
    <div>
        <span>Hello React</span>
    </div>
)

总结:这里就可以看出来 jsx 的优势了,它能够很轻松地创建虚拟 DOM (但实际上,它还是会翻译成上面的结果,只是我们写起来方便,就是个语法糖而已)

1.2.4. VDOM 是什么

  • 虚拟 DOM 实际上是 Object
  • 虚拟 DOM 比较,它只需要 react 内部使用,就不需要那么多真实 DOM 的属性
  • 虚拟 DOM 最终会被渲染成真实 DOM,放在页面上

在这里插入图片描述

1.2.5. jsx(JavaScript XML)

如下是 JSX 的一些语法规则:

  • 定义虚拟 DOM 时,不能有引号
  • 标签内有 表达式 时,得用 { username }
  • 样式要用 className = "username"
  • 内联样式用 { { color: 'red' }},可以看成 {} 传入了一个对象 { color: ‘#f00’ }
  • 只能有一个 根标签,如果要写多个兄弟节点,就只能在外层包一层
  • 标签 必须闭合,否则报错,如:<input type="text"/>
  • 尽量别乱写标签,如:<good>123</good>,小写开头的标签会自动转换成 HTML 元素,控制台会报错;大写开头就是 组件,如果没有定义的话,也会报错
    // 例子
    const id = 'username'
    const username = 'yuwan'
    const VDOM = (
    		<h1 id={id} className="username">{ username.toLowerCase() }
      			<span style={
        { color: '#f00', fontSize: '30px' }}></span>
    		</h1>      
    )
    

Tip:表达式代码 的区别:
1.表达式返回一个值,比如:username、a+b、add(1, 3)【左侧写一个变量,能够接收到的就是表达式】
2.比如这些就是代码而不是表达式:if() 、{}、 for(){}、 switch(){}等

1.2.6. 小案例 - 动态生成前端框架名称

const title = '前端 js 框架列表'
const frameworks = ['Angular.js', 'React.js', 'Vue.js']
const VDOM = (
    <div>
        <h1>{
   title}</h1>
        <ul>
            {
   
                // 这里是不能写 forEach 来遍历,因为它没有返回值;写 map 才能动态生成出来
                frameworks.map((item, index) => {
   
                    return <li key={
   index}>{
   item}</li>
                })
            }
        </ul>
        <p>
            {
   
            }
        </p>
    </div>
)
ReactDOM.render(VDOM, document.getElementById('root'))

1.2.7. 模块、组件、模块化、组件化的理解

1.2.7.1. 模块
  • 理解:一般就是一个 js 文件,就是一个模块
  • 为什么分模块:按照业务逻辑增加,代码会增多且复杂
  • 作用:复用 js,简化 js 的编写,提高 js 运行效率
1.2.7.2. 组件
  • 理解:用来实现一些功能的 代码和资源 的集合(每个组件有自己的 HTML、CSS、JS、Video、image,简言之就是什么都拆了)
  • 为什么分组件:一个界面的功能更加复杂的时候,分组件就能更好地复用代码
  • 作用:复用代码,简化项目编码,提高运行效率
1.2.7.3. 模块化

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

1.2.7.4. 组件化

当应用都是以组件方式来进行开发,那么这个应用就是一个组件化的应用

1.3. react 面向组件编程

1.3.1. 定义组件

react 中,组件有两种:函数式组件类式组件

1.3.1.1. 函数式组件

粘贴 CreateApp 代码,在线查看 babel 转换结果

渲染过程:

  • 1.React 解析组件标签,找到 CreateApp 组件(若找不到则会报错)
  • 2.发现 CreateApp 是使用函数定义的,因此就会调用该函数,将返回的虚拟 DOM 渲染为真实 DOM,随后呈现在页面中

注意:

  • babel 在转换过程中开启了严格模式,导致 this 不能指向 window,因此是 undefined
<script type="text/babel">
    function CreateApp() {
    
        console.log(this) // undefined
        return <h1>我是函数式组件,我适合于简单组件的创建</h1>
    }
    ReactDOM.render(<CreateApp/>, document.getElementById('app'))
</script>

这里 render(CreateApp(), …) 也会呈现出内容,但是它不是个组件了,在 Console -> Components 下无法找到

1.3.1.2. 类式组件

类知识复习

<script>
  class Person {
    
          constructor(name, age) {
     // 构造器中的 this 指向的是实例对象,new Person() 的谁就指向谁
              this.name = name // 构造器是可以不写的,因为继承
              this.age = age
          }
          speak() {
     // 一般方法:speak 放在了哪里? 原型对象上,供所有实例都能够调用
              // 这里 this 指向函数调用的对象。可能是 Person 实例对象,也可能是 call、bind、apple 等改变 this 指向的对象
              console.log(`我叫${
      this.name},我今年 ${
      this.age}岁啦!`)
          }
      }
      const p1 = new Person('zhang', 18)
      console.log(p1)
      p1.speak()
      p1.speak.call({
    name:'yuwan', age:20})
      console.log('----------华丽的分割线-----------')
    
  class Student extends Person{
    
          constructor(name, age, grade) {
    
              super(name, age); // 一旦 Student 继承 Person 而且写了 constructor,必须调用 super() 而且是第一句调用
              this.grade = grade
          }
          speak() {
    
              console.log(`我叫${
      this.name},我今年 ${
      this.age}岁啦,我读${
      this.grade}年级`)
          }
      }
      const s1 = new Student('yuwan', 22, '研究生')
      console.log(s1)

      s1.speak() // 根据原型链的查找方式,会先找 Student 原型对象 - Person 的 speak 方法,从而实现覆盖 Person 原型对象的 speak 方法
</script>

总结:

  • constructor 可写可不写,具体看要求

  • class Son extends Father,且 Son 写了 constructor,就必须调用 super()【可以简化编码】

  • 类中定义的一般方法,放在了类的原型对象上,供所有实例使用
    在这里插入图片描述

  • 注意 this 的指向【构造器中,this 指向的是 new Person();一般方法的 this就要看具体情况了】

  • 注意原型链查找方式

在这里插入图片描述

渲染过程:

  • 1.react 解析标签,找到 MyApp 组件
  • 2.发现这个组件是类定义的,就会 new MyApp() 然后调用了 render 方法
  • 3.将 render() 返回的虚拟 DOM 渲染到页面的真实 DOM 中
<script type="text/babel">
  class MyApp extends React.Component {
    
      render() {
     // 这个方法在 MyApp 的原型对象上,供所有 MyApp 实例对象调用
          return <h1>我是类式组件,适用于较复杂的组件</h1>
      }
  }
  ReactDOM.render(<MyApp/>, document.getElementById('app'))
</script>

1.3.2. 组件核心属性之 state

理解:简单理解就是组件自身所需要的数据 ;组件被称为状态机,通过更新组件的 state 来更新对应的页面显示(重新渲染组件)

注意事项:

  • 组件中 render 的 this 指向了组件实例
  • 组件中自定义方法中 this 为 undefined,怎么解决?(bind、()=>{})
  • 状态中的数据不可直接修改,通过 setState 修改
<script>
class MyComponent extends React.Component{
    
    constructor(props) {
    
        super(props); // 按照上面所说,有继承且写了 constructor 就必须要调用 super
        this.state = {
     isHot: true } // 初始化 state。当前组件的 state 是一个对象,便于保存多种类型的数据
    }
    render() {
    
        const {
     isHot } = this.state
        return <h1>今天天气很{
     isHot? '炎热':'凉爽'}</h1>
    }
}
ReactDOM.render(<MyComponent/>, document.getElementById('app'))
</script>
1.3.2.1. 点击事件

原生 JavaScript 的点击事件分为三种写法,React 推荐第三种写法

const btn1 = document.getElementById('btn1')
btn1.addEventListener('click',() => {
   
    alert('hello world')
})
const btn2 = document.getElementById('btn2')
btn2.onclick = () => {
   
    alert('hello world')
}
// <button οnclick="test()">按钮3</button>
function test() {
   
    alert('hello world')
}
1.3.2.2. 类中方法 this 指向

类中的函数默认开启了严格模式,导致直接通过 varSpeak() 调用时,会输出 undefined

<script>
    class Person {
    
        constructor(name,age) {
    
            this.name = name
            this.age = age
        }
        speak() {
     // 默认是开启了局部严格模式
            console.log(this)
        }
    }
    const p1 = new Person('tom', 19)
    p1.speak() // Person {name: 'tom', age: 19}
    const varSpeak = p1.speak
    varSpeak() // undefined
</script>
1.3.2.3. React 绑定事件

如下是演示,我们在不知道 react 怎么绑定事件的过程:首先想到的是传函数调用结果 -> 传表达式调用结果 -> 传函数名 -> 解决 this -> this.xxx 调用

<script>
class MyApp extends React.Component{
    
    // ...
  render() {
    
    return <h1 onClick="test()"></h1>
  }
}
function test(){
    
    console.log('this is test message.')
}
// ERROR: Expected `onClick` listener to be a function, instead got a value of `string` type.
// 1.本来点击事件要回调函数,但是这样写就是传给它一个 string,因此报错

return <h1 onClick={
     test() }></h1>
// ERROR: 控制台直接输出:this is test message.
// 2.这相当于把 test() 的返回值传给了 onClick 作为回调函数,而 test() 执行就会打印输出,进而返回 undefined,因此此时点击是无响应的

return <h1 onClick={
     test }></h1>
// 3.这里点击就可以输出: this is test message.
// 由于函数写在类外部,我们获取不到 MyApp 实例对象,因此在 test 方法中无法操作 MyApp 实例对象的 state

class MyApp extends React.Component{
    
  // ...
  render() {
    
    return <h1 onClick={
     test }></h1>
  }
  test(){
    
    console.log(this)
    console.log('this is test message.')
  }
}
// ERROR:  test is not defined
// 4.因为在一个类中的方法体里,调用类的其他方法,肯定得要用 this.xx 才能调用


return <h1 onClick={
     this.test }></h1>
// 点击 h1,执行 test() 输出 undefined
// 正如前面一节,类中 this 指向,相当于 onClick = this.test; 在某个时刻,onClick() 这样调用了,而类中函数开启了严格模式,因此输出 undefined
</script>

绑定事件的正确用法

有两种方式:bind 来改变 this利用箭头函数的特点

<script>
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值