IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> React学习 day-02 -> 正文阅读

[JavaScript知识库]React学习 day-02

day-02

组件的状态

关于状态

概念

状态就是用来描述事物在某一时刻的的数据,例如:9 月 23 号时书的库存数量;18 岁时人的身高等。

特点

状态能被改变,改变了之后视图会有对应的变化。

作用

  • 保存数据。
  • 数据变化响应到视图(React 包内部的操作)。

有状态/无状态组件

  • 有状态组件:能定义 state 的组件,类组件就是有状态组件
  • 无状态组件:不能定义 state 的组件,函数组件一般叫做无状态组件

🧐 2019 年 02 月 06 日,React v16.8 中引入了 React Hooks,从而函数式组件也能定义自己的状态了。

无状态组件的应用场景

  • 组件本身就不需要有状态,例如渲染一段静态的内容。
  • 组件本身就没有状态,有可能只需要从外部传入的状态就够了。

类组件的状态

目标

掌握 React 类组件中如何定义和使用状态。

定义

第一种方式:在 constructor 中通过 this.state = {}

class App extends React.Component {
    //继承的时候,子组件一旦有constructor,constructor内部必须调用super()
    constructor() {
        //super要放到this的前面
        super()
        this.state = {
            list: [
                { id: 1, name: '明天会更好' },
                { id: 2, name: '今天' },
            ],
        }
    }
}

第二种方式:通过 state 来定义状态,state 对应的值必须是一个对象

class App extends React.Component {
    state = {
        list: [
            { id: 1, name: '明天会更好' },
            { id: 2, name: '今天' },
        ],
    }
    // ...
}

🧐 思考两种方式的差异?

两种定义状态的差异:

ocnstructor中定义,new的时候可以传参,传递的参数可以当做状态

而state={ }不方便传参

事件绑定

目标

  • 掌握 React 中如何进行事件绑定。
  • 掌握 React 中如何获取事件对象。

语法

<元素 事件名1={事件处理函数1} 事件名2={事件处理函数2}></元素>

注意:React 事件名采用驼峰命名法,比如 onClick、onMouseEnter 等。

类组件中事件绑定

需求:点击按钮控制台打印 ‘Hello World’。

class App extends React.Component {
    handleClick() {
        console.log('Hello World')
    }
    render() {
        return <button onClick={this.handleClick}>click</button>
    }
}

函数式组件中的事件绑定

const App = () => {
    const handleClick = () => {
        console.log('Hello World')
    }
    return <button onClick={handleClick}>click</button>
}

获得事件对象

通过形参 e 可以拿到事件对象,例如 e.target 就是触发事件的那个 DOM 元素。

小结

  • 事件命名的规则是什么?

    驼峰命名法

  • 如何拿到事件对象?

    e.target

解决 this 指向问题

直接调用类中的方法,this指向的是undefined

高阶函数:返回函数的函数,函数作为参数传递的函数 例如:arr.map(()=>{})

柯里化:通过函数调用继续返回函数的形式,实现多次接收参数最后统一处理的函数编码形式。

方法 1

高阶函数:通过 this 来直接调用 handleClick 并返回箭头函数。

🧐 柯里化:通过函数调用继续返回函数的形式,实现多次接收参数最后统一处理的函数编码形式。

class App extends React.Component {
    state = {
        count: 0,
    }
    handleClick() {
        // 这里的 this 指向是什么?那就看是谁调用的!
        return () => {
            console.log(this.state.count)
        }
    }
    render() {
        return (
            <div>
                <h2>计数器:{this.state.count}</h2>
                <button onClick={this.handleClick()}>+1</button>
            </div>
        )
    }
}

方法 2

包裹一层箭头函数。

箭头函数中的 this 指向“外部”,即 render 函数,而 render 函数中的 this 正是组件实例。

class App extends Component {
    state = {
        count: 0,
    }
    handleClick() {
        console.log(this.state.count)
    }
    render() {
        return (
            <div>
                <h2>计数器:{this.state.count}</h2>
                <button onClick={() => this.handleClick()}>+1</button>
            </div>
        )
    }
}

方法 3

使用 bind。

bind谁,handleClick中的this就是谁

class App extends Component {
    state = {
        count: 0,
    }
    handleClick() {
        console.log(this.state.count)
    }
    render() {
        return (
            <div>
                <h2>计数器:{this.state.count}</h2>
                <button onClick={this.handleClick.bind(this)}>+1</button>
            </div>
        )
    }
}

扩展

es6 语法:

🤔 关于 class 中的实例方法和原型方法?

原型方法演示

class App {
    handleClick() {}
}

const app1 = new App()
const app2 = new App()
// 通过打印也能发现 handleClick 确实是挂载到原型上的
console.log(app1)
// 每一个实例访问到的都是挂载到原型上的方法,所以等价
console.log(app1.handleClick === app2.handleClick)

实例方法演示

class App {
    //直接在class内部通过等号赋值的是挂载到实例上的
    handleClick = () => {}
}

const app1 = new App()
const app2 = new App()
// 通过打印也能发现 handleClick 确实是挂载到实例上的
console.log(app1)
// 每一个实例访问到的都是挂载到自己上的方法,所以不等价
console.log(app1.handleClick === app2.handleClick)

所以,要明白在 class 中直接写的方法和通过赋值语句添加的方法本质上不一样。

在 class 中直接写的方法是原型方法

在 class 中通过赋值语句添加的方法是实例方法

es5语法 :

注意:在 constructor 中挂载的方法也是实例方法。

注意:语法规范:继承的时候,子组件一旦有constructor,constructor内部必须调用super()

静态属性

通过:static 挂载

    class App{
        //静态属性
        static age=18
    }
        //静态属性
    App.gender='男'
    console.log(App.age)

原型链:

多个对象之间通过 proto 链接起来的这种关系就是原型链

a ==> App ==> Object.prototype

方法 4

通过赋值语句往实例上面添加一个箭头函数。

class App extends Component {
    state = {
        count: 0,
    }
    handleClick = () => {
        console.log(this.state.count)
    }
    render() {
        return (
            <div>
                <h2>计数器:{this.state.count}</h2>
                <button onClick={this.handleClick}>+1</button>
            </div>
        )
    }
}

证明“外层” this 确实是组件实例

class App {
    temp = this
}

const app = new App()
console.log(app === app.temp)

方法 5

在构造函数中再创建一个实例方法,和原型方法公用一个函数体。

class App extends React.Component {
    constructor() {
        super()
        this.state = {
            count: 0,
        }
        // 1. 往实例自身上又挂载了一个 handleClick 函数
        // 2. 此函数的函数体是通过原型上 handleClick 函数生成的新函数
        // 3. 并把原型上 handleClick 函数中的 this 通过 bind 绑定为了 this,而这里构造函数中的 this 正是实例对象
        // 4. 其实点击的时候调用的是这个构造函数 handleClick(就近原则),而这个构造函数中的 handleClick 执行的是原型上的 handleClick 的函数体
        this.handleClick = this.handleClick.bind(this)
    }
    handleClick() {
        console.log(this.state.count)
    }
    render() {
        return (
            <div>
                <h2>计数器:{this.state.count}</h2>
                <button onClick={this.handleClick}>+1</button>
            </div>
        )
    }
}

修改状态

不要直接修改原数据

目标

掌握通过 setState 修改状态的写法。

错误写法

this.state.count += 1 // 数据确实也会变,但不是响应式的!

内容

  • 语法:this.setState({ 要修改的部分数据 })
  • 作用:修改 state 并更新视图。
  • 来源:setState() 函数是通过继承而来的。
  • 注意:setState() 的操作是合并,不会影响没有操作到的数据。
this.setState({ count: this.state.count + 1 })

小结

通过哪个方法来修改 state 中的数据?

this.setState( )

状态的不可变性

目标

了解 React 的核心理念,状态的不可变性。

解释

也就是说不要直接修改原数据,而是要产生一份新数据,然后通过 setState() 用新的数据覆盖原数据,这么做的其中一个重要原因就是为了 SCU(shouldComponentUpdate),为了性能优化。

受控表单组件

目标

能够使用受控组件的方式收集到表单中的数据。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-23cEQY53-1638796961376)(react.assets/ifer_form.png)]

概念

受控不受控一般是针对表单来说的,所谓受控表单组件,即表单元素的 value 值受到了 React 中状态(state)的控制(对状态的操作会影响视图,视图的变化又会反映到状态上)。

input

  1. 在 state 中添加一个状态,作为表单元素的 value 值(数据影响视图)。
  2. 给表单元素绑定 onChange 事件,将表单元素的值设置为 state 的值(视图影响数据)。

textarea

操作方式和 input 框一样。

select

radio

多个单选按钮,绑定的值可以是一个字符串。

checkbox

绑定的值可以是一个数组。

import React, { Component } from 'react'

export default class App extends Component {
  state = {
    userName: 'zs',
    info: 'qweqwewq',
    frame: 'vue',
    gender: 'male',
    checkbox: ['orange'],
  }

  handelChange = (e) => {
    console.log(e.target.type)
    if (e.target.type !== 'checkbox') {
      this.setState({
        [e.target.name]: e.target.value,
      })
    } else {
      if (e.target.checked) {
        this.setState({
          [e.target.name]: [...this.state.checkbox, e.target.value],
        })
      } else {
        //方法二:将点击的那一项筛选出去
        const tempCheckbox = [...this.state.checkbox].filter((item) => {
          return item !== e.target.value
        })
        this.setState({
          [e.target.name]: tempCheckbox,
        })
        //方法一:寻找点击的那一项的索引,删除
        // const tempCheckbox = [...this.state.checkbox]
        // const index = this.state.checkbox.indexOf(e.target.value)
        // if (index !== -1) {
        //   tempCheckbox.splice(index, 1)
        //   this.setState({
        //     [e.target.name]: tempCheckbox,
        //   })
        // }
      }
    }
  }

  render() {
    const { userName, info, frame, gender, checkbox } = this.state
    return (
      <ul>
        <li>
          <label htmlFor="userName">用户名</label>
          <input
            type="text"
            id="userName"
            name="userName"
            value={userName}
            onChange={this.handelChange}
          ></input>
        </li>
        <li>
          <label htmlFor="info">其他信息</label>
          <textarea
            id="info"
            name="info"
            value={info}
            onChange={this.handelChange}
            cols="30"
            rows="10"
          ></textarea>
        </li>
        <li>
          <label htmlFor="frame">框架</label>
          <select
            id="frame"
            name="frame"
            value={frame}
            onChange={this.handelChange}
          >
            <option value="react">react</option>
            <option value="vue">vue</option>
            <option value="Angular">Angular</option>
          </select>
        </li>
        <li>
          <label>
            男:
            <input
              type="radio"
              value="male"
              name="gender"
              checked={gender === 'male'}
              onChange={this.handelChange}
            ></input>
          </label>
          <label>
            女:
            <input
              type="radio"
              value="female"
              name="gender"
              checked={gender === 'female'}
              onChange={this.handelChange}
            ></input>
          </label>
          <label>
            未知:
            <input
              type="radio"
              value="unknown"
              name="gender"
              checked={gender === 'unknown'}
              onChange={this.handelChange}
            ></input>
          </label>
        </li>
        <li>
          <label>
            Apple
            <input
              type="checkbox"
              value="Apple"
              name="checkbox"
              checked={checkbox.includes('Apple')}
              onChange={this.handelChange}
            ></input>
          </label>
          <label>
            orange
            <input
              type="checkbox"
              value="orange"
              name="checkbox"
              checked={checkbox.includes('orange')}
              onChange={this.handelChange}
            ></input>
          </label>
        </li>
      </ul>
    )
  }
}

非受控表单组件

概念

非受控组件则是通过操作 DOM 的方式来获取数据,表单中的 value 并没有和 state 中的数据进行绑定。

内容

通过 React.createRef() 获取 DOM。

import React, { Component } from 'react'

export default class App extends Component {
    // Step1
    input = React.createRef()
    handleChange = () => {
        // Step3
        console.log(this.input.current.value)
    }
    render() {
        return (
            <div>
                {/* Step2 */}
                <input ref={this.input} type='text' placeholder='输入内容' onChange={this.handleChange} />
            </div>
        )
    }
}
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-07 11:56:25  更:2021-12-07 11:58:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:27:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码