React基本使用(持续更新)

1. react是什么 ?

  • react是用于构建用户界面的JavaScript库

  • 构建用户界面(User Interface,简单理解为: HTML页面)

  • JavaScript库,不是框架,是库

  • Vue是渐进式的JavaScript框架

  • react全家桶是框架

    • react:核心库

    • react-dom: dom操作

    • react-router: 路由

    • reactx: 集中状态管理

2. 创建react脚手架

创建方式一

  1. 全局安装脚手架工具包,

    命令: npm i -g create-react-app

  2. 用脚手架创建项目

    命令:create-react-app 项目名称

创建方式二

  1. 直接使用npx来创建项目

    命令: npx create-react-app 项目名称

    解释:

  • npx create-react-app是固定的命令, create-react-app是react脚手架的名称
  • npx不是直接在本地创建脚手架,并且npx下载的都是最新版本的react
  • npx 是 npm v5.2 版本新添加的命令,用来简化 npm 中工具包的使用

3. 启动项目

  • npm run start 或npm start
  • webpack会实时自动打包,并把代码嵌入到public/index.html文件中,并执行。

接下来我们继续写代码,尝试第一次用react构建一个我们的页面

步骤

  1. 导入包 : React , ReactDOM (注:在16.8版本后,可以不用导入React)
  2. 创建react元素
  3. 渲染元素到dom上

示例

在页面上创建一个h1标题

代码位置: index.js

// 导入react 和react-dom
import React from 'react'
import ReactDOM from 'react-dom'

// 创建元素
const header = React.createElement('h1',{id:'myH1'},'Hello React!')

// 渲染react元素
ReactDOM.render(header,document.getElementById('root))

解释:

  • 在创建元素步骤中React.createElement('h1',{id:'myH1','Hello React!'})
  • 参数一: 标签名称
  • 参数二: 属性,不想写可以为空对象,或者为null,不可省略
  • 参数三: 内容

扩展: 在渲染react元素中,我只渲染了一个header,如果有多个,你可以写成数组的形式 ReactDOM.render([header,xxx,xxxx,xxxx],document.getElementById('root))

Reacte.createElement的格式

React.createElement('标签名',{标签上的属性1:值},子元素1,子元素2)

4. JSX的使用

由于Reacte.createElement的效率实在太低了,创建一个标签元素还可以,如果是多个,或者一整个页面,那要写到什么时候呢 ?

  • 繁琐不简洁
  • 不直观,无法一眼看出所描述的结构
  • 不优雅,开发体验不友好

JSX是什么 ?

JSX: 是在JavaScript XML 缩写

  • 在 js 代码中书写XML代码,可以理解为在 js 中写 HTML

    • 注意: JSX 不是标准的 js写法 , 是 js 的语法扩展, 脚手架中配置了’@/babel/plugin-transform-react-jsx’包, 用来解析该语法
  • react用它来创建 UI (HTML) 结构

可以理解为: 以前我们用HTML来书写页面,现在用jsx来书写页面

示例

import React from 'react'
import ReactDOM from 'react-dom'

const list = <ul><li>html</li><li>js</li><li>css</li></ul>

ReactDOM.render(list,document.getElement('root')

优势

  • 采用类似于HTML 的语法, 降低了学习的成本, 会HTML就会 JSX
  • 充分利用了 JS 自身的能力来创建 HTML 结构 . 比如, 利用 JS 数组的 map 方法创建列表结构

JSX 是如何工作的

babel在线使用

原理: JSX — babel — React.createElement
在这里插入图片描述

5. JSX 的注意事项

JSX 必须要有一个根节点

有两种格式:

  • 格式一: <> xxx </>
import ReactDOM from 'react-dom'

const header = <><h1>Hello React</h1></>

ReactDOM.render(header, document.querySelector('#root'))

// 错误写法  
const header = <h1>你应是一场梦</h1><p>我是一阵风</p>

外边必须要有一个父盒子包裹,如果你不想在页面中的element中看见他,可是使用<></>进行包裹

  • 格式二: <React.Fragment> xxx </React.Fragment>
import ReactDOM from 'react-dom'

const header = <React.Fragment><h1>你应是一场梦</h1><p>我是一阵风</p></React.Fragment>

ReactDOM.render(header, document.querySelector('#root'))

属性名不能用 js 中的关键字

例如 class, for

  • class – className
  • for – htmlFor

单标签要闭合

  • <input><input/>

换行建议使用 ( ) 包裹

const content = (
	<div>
  	<h1>xxx</h1>
  </div>
)

老版本 (16.8) 先引入 react 才能使用 jsx

理解引入react的作用(提供createElement的功能)

老版本中不引入就会报错 React must be in scope when using JSX

五个注意事项

  1. jsx 必须要有一个根节点
  2. 属性名不能用 js 中的关键字, 例如 class , for
  3. 单标签要闭合
  4. 换行建议使用 ( ) 包裹
  5. 老版本 (16.8) 先引入 react 才能使用 jsx

6. 嵌入表达式 (重点)

嵌入表达式的格式

{ JS 表达式}

例如:

const ReactDOM from 'react-dom'

const num = Math.random()
const content = (<div>
                  {num}
                 <div>)
                 
ReactDOM.render(content, document.querySelector('#root'))

大括号是一种特殊的语法: 让 JSX 解析器知道它需要将它们之间的内容解释为 JavsScript代码, 并输出结果

嵌入表达式的位置

  1. 属性值
const logo = 'https://create-react-app.dev/img/logo.svg'

cosnt pic = <img src={logo} />
  1. 内容
const name = '张三'
const person = <div>{name}</div>```

单花括号中可以写那些内容?

可以写:

  1. 表达式

    定义: 数据类型和运算符的组合 (可是单独出现数据类型, 也可以数据类型 + 运算符的组合)

    特点: 有值 (或者能够计算出一个值), 能被console.log()

  2. 其他的 jsx 表达式

  3. 注释

不可以写:

  1. 对象

    注意点: <div style={{width:'200px'}}>xxx</div>,行内样式表达式内是对象,这种是特殊情况

  2. js 语句: if 语句 , switch-case 语句 , 变量声明语句

示例

import React from 'react'
import ReactDOM from 'react-dom'

const girl = {
  name: '小芳',
  age: 19,
  logo: 'https://create-react-app.dev/img/logo.svg',
  skills: ['唱歌', '收稻子']
}

const f1 = () => {
  return <i>{girl.skills.join(',')}</i>
}
const baseInfo = (
  <div>
    姓名: {girl.name}
    妙龄: {girl.age}
  </div>
)

const content = (
  <div style={{ padding: 50 }}>
    <h1>jsx-表达式</h1>

    {/* 1. {} 可以用在内容上 */}

    {/* {}可以包其他的jsx */}
    {baseInfo}

    {/* {}可以包表达式 */}
    <p>爱好:{girl.skills}</p>
    <p>字符串:{'abc'}</p>
    <p>字符串:{'{'}</p>
    <p>数组:{[1, 2, 3]}</p>
    <p>数值:{100}</p>
    <p>函数:{f1()}</p>
    <p>算数表达式:100/2={100 / 2}</p>
    <p>
      三元表达式:{girl.age < 28 ? '芳龄' : '年龄'} {girl.age}
    </p>

    {/* 2. {}可以用在属性值上 */}
    <p className={['class1', 'class2'].join(' ')}>类名组合</p>
    <img width="80" src={girl.logo} />

    {/*
    下面是错误的示范
    不能输出对象,不能使用语句
    <p>{{ a: 1 }}</p>
    <p>{var a =1 }</p> */}
  </div>
)
ReactDOM.render(content, document.getElementById('root'))

7. JSX- 条件渲染

  • if/else
  • 三元运算符
  • 逻辑与(&&)运算符

示例

简单情况 - 用三元表达式

const flag = 0
const concent = (<div>{flag ? '我爱你' : '我不爱你'}</div>)```

复杂情况 - 使用额外的函数

// 这里我直接写的是箭头函数,当然你也可以写成声明式
const loadData = (isLoading) => {
  if (isLoading) {
    return <div>数据加载中,请稍后...</div> 
  } else {
    return <div>数据加载完成,此处显示加载后的数据</div>
  }
}
const content = <div>{loadData(true)}</div>

8. JSX 列表渲染

在 JSX 中使用数组的 map 方法来生成列表结构,需要给渲染的 标签元素添加 key属性,必须是唯一值,跟vue一样

示例

从后端拿回来的数据保存在数组中,需要用列表来展示, 数组内容如下:

const skills = [
  { id: 1, name: 'html' }, 
  { id: 2, name: 'css' }, 
  { id: 3, name: 'js' }
]

而我们要生成如下 dom 结构 :

<ul>
  <ol>技能1:html</ol>
  <ol>技能2:css</ol>
  <ol>技能3:js</ol>
</ul>

笨方法

直接定义一个数组,每个元素都是一个jsx结构

const skills = [<ol>技能1:html</ol>, <ol>技能2: css</ol>, <ol>技能3: js</ol>]

const content = <ul>{skills}</ul>

ReactDOM.render(content, document.getElementById('root'))

用 map 方法

完整格式

// 完整格式
const t = skills.map((item) => {
  return <ol>技能{item.id}: {item.name}</ol>
})

const list = <ul>{t}</ul>```

简写格式

const list = (
  <ul>
    {skills.map(item => <ol>技能{item.id}: {item.name}</ol>)}
  </ul>
)

9. 列表渲染中的 key

react 内部用来进行性能优化时使用的,在最终的HTML结构中是看不到的。

例如: 数据如下

const songs = [
  { id: 1, name: '痴心绝对' }, 
  { id: 2, name: '像我这样的人' }, 
  { id: 3, name: '南山南' }
]

生成的 dom

<ul>
  <li>排名:1 - 歌名:痴心绝对</li>
  <li>排名:2 - 歌名:想我这样的人</li>
  <li>排名:3 - 歌名:南山南</li>
</ul>
  • 如果添加一条数据,则视图也要随之更新,而更新的逻辑是:前三条正常保留,而重新添加第四条。
  • 如果数据中有一个唯一的属性值,就可以使用这个属性来当做key, 如果没有,就可以用索引值

10. JSX 样式处理

行内样式 - style

格式:

<dom元素 style={ {css属性1:值1,css属性2:值2} }></dom元素>

示例:

// 行内样式
<h1 style={ {color: 'red', width: 200, backgroundColor: 'black'} }>
  我是黑底红字的h1
</h1>

使用 className

  • 用className (注意: 不是class) 定义类名
  • 把样式写在额外的.css文件中 , 然后引入 .css文件
import './index.css'

// 类名
<h1 className="title">
  我是黑底红字的h1
</h1>

补充.css

import './index.css'

// 类名
<h1 className="title">
  我是黑底红字的h1
</h1>

11. 环境配置 - 引入 eslint

步骤:

  1. npm i eslint -D

  2. 在项目根目录, 运行 npx eslint --init

    1. 按交互提示安装相关插件
    2. 它会自动生成 eslint 得到配置文件
  3. 设置 vscode 的自动保存格式化

eslint的相关选择

可以根据我打 √ 的进行选择
1.
在这里插入图片描述
2.
在这里插入图片描述
它的问是: 你想如何配置 eslint ?

选项一: 检查语法

选项二: 检查语法,并发现问题

选项三: 检查语法,发现问题,并执行你的代码风格

3.
在这里插入图片描述
你想使用什么类型的模块 ?

选项一: JavaScript modules (import / export)

选项二: CommonJS (require / exports )

选项三: 以上均不

4.
在这里插入图片描述
你项目有什么框架 ?

选项一: React

选项二: Vue.js

选项三: 以上均不

5.
在这里插入图片描述
你的项目使用 typescript吗 ?

根据自己的需求选,就算不用typescript ,选了也没事

6.
在这里插入图片描述
代码在哪里运行 ? (按空格选中,回车确认)

选项一: 浏览器中

选项二: Node 环境中

7.
在这里插入图片描述
如何定义你的项目代码风格 ? (自行选择,不是唯一答案)

选项一: 使用市面上流行的风格

选项二: 问你一些问题,判断你的风格

选项三: 检查你的 JavaScript代码,判断风格

8.
在这里插入图片描述
eslint配置文件是什么格式 ?

选项一: JavaScript

选项二: YAML

选项三: JSON

后面还有个问题是,问你是否使用npm 下载 ,选 yes

配置

在setting.json中,配置如下

{
  "eslint.run": "onType",
  "eslint.options": {
    "extensions": [".js", ".vue", ".jsx", ".tsx"]
  },
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}

12. 环境配置 - 引入 prettier - now

eslint并不能深入到jsx代码中来格式化,所以需要额外的工具。

prettier-now

是prettier项目的分支,具备和prettier一样的功能,不过,它允许使用更多的配置项。在vscode的插件库中,同时有prettier-now和prettier,在安装时,请不要安装错了。

步骤:

  1. 安装vscode插件 prettier-now
  2. 补充配置
{
  "eslint.run": "onType",
  "eslint.options": {
    "extensions": [".js", ".vue", ".jsx", ".tsx"]
  },
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },

  // 编辑器设置 - 保存时做格式化
  "editor.formatOnSave": true,
  // 编辑器设置 - 默认采用prettier-now做格式化
  // 如果使用的是prettier,这的设置应该是 esbenp.prettier-vscode
  "editor.defaultFormatter":"remimarsal.prettier-now",

  // 控制缩进
  "prettier.useTabs": false, // 缩进不使用tab,使用空格 
  "prettier.tabWidth": 2, // 缩进字节数
  
  // 函数声明时小括号前后要加空格
  // 如果你使用prettier这一项是不能做选择的,导致和eslint默认配置的冲突
  // 可以在百度中搜到很多的记录: https://www.baidu.com/s?wd=prettier%20%E5%87%BD%E6%95%B0%E7%A9%BA%E6%A0%BC
  "prettier.spaceBeforeFunctionParen": true,

  // react的jsx让>与结束标签同行
  "prettier.jsxBracketSameLine": true,

  "prettier.semi": false, // 不要给语句加;
  "prettier.singleQuote": true, // 采用单引号
  "prettier.trailingComma": "none", // 不要尾随逗号,
  "prettier.printWidth": 80, // 每行超过80列就换行

  // 在.js中,写div按下tab就可以自动补全,而不需要写<div再补全
  "emmet.includeLanguages": {
    "javascript": "javascriptreact"
  },
}

13. 组件

  • 对特定功能的封装, 主要用来对 UI 进行拆分
  • 内容: HTML — CSS — JS
  • 特点: 独立, 可复用, 可组合

分类

  • 基础组件: 指input, button这种基础标签, 以及antd封装过的通用 UI 组件
  • 业务组件: 由基础组件组合成的业务抽象化 UI , 例如: 包含了公司所有部门信息的下拉框
  • 区块组件: 由基础组件和业务组件组合成的 UI块
  • 页面组件: 展示给用户的最终页面, 一般就是对应一个路由规则

14. 组件的两种创建方式

  1. 使用 JS 中的函数创建组件
  2. 使用 JS 中的 class 创建组件

示例

import React from 'react'
import ReactDOM from 'react-dom'

// 函数式组件
const Com1 = () => {
  return <div>函数组件</div>
}

// 类组件
class Com2 extends React.Component {
  render () {
    return <div>类组件</div>
  }
}

cosnt content = (
  <div>
  <Com1 />
  <Com2 />
  </div>
)

ReactDOM.render(content,document.getElementById('root'))

对比

  1. 类组件比较繁琐
  2. 函数式组件比较简便
  3. 都可以使用, 没有谁好谁坏

15. 函数式组件 - 使用函数创建组件

使用 JS 的函数(或者箭头函数) 创建的组件, 叫做 函数组件

  • 函数名首字符要大写

    必须以大写字母开头, react以此区分组件和普通的 HTML

  • 必须要有返回值

表示该组件的 UI 结构 , 如果不需要渲染任何内容, 则返回 null

// 1. 普通函数创建组件
function Hello () {
  return <div>这是函数组件</div>
}

// 2. 箭头函数创建组件
const Hello = () => <div>这也是函数组件</div>

使用组件

使用组件就像使用 HTML 标签一样 , 用函数名称作为组件标签名称

// 双标签
<Hello></Hello>

// 单标签
ReactDOM.render(<Hello />,document.getElementById('root'))

16. 类组件 - 用 class 创建组件

格式:

使用 ES6 的 class 创建的组件, 叫做类(class) 组件

// class 类名 extends React.Component {}
import React from 'react'

class Hello extends React.Component {
  render () {
    return <div> 这是我用类创建的组件 </div>
  }
}

注意点:

  1. 类名必须以 大写字母开头
  2. extends 是一个 关键字 , 用来实现类之间的继承, 类组件应该继承 React.Component 父类, 从而使用父类中提供的方法和属性
  3. 类组件必须提供 render 方法, render 方法必须要有返回值, 表示该组件的 UI 结构, render会在组件创建时执行一次
import React from 'react'

class Hello extends React.Component {
  render () {
    return <div> Hello Class Component!! </div>
  }  
}

使用组件

// 导入 React
import React from 'react'
import ReactDom from 'react-dom'
// 1. 定义组件
class Hello extends React.Component {
  render() {
    return <div>Hello Class Component!</div> 
  }
}

const content = (<div><Hello/></div>)

ReactDOM.render(content, document.getElementById('root'))

使用组件的方式和函数式组件一样 : 可使用单标签和双标签

17. 有状态组件和无状态组件

定义: 是 用来描述事物在某一时刻形态的数据, 一般称为 state , 例如: 11月6日书的库存数量; 18岁时人的身高

特点:

  • 状态能被改变, 改变了之后视图会有对应的改变
    在这里插入图片描述
    作用:

  • 保存数据: 例如要循环生成一份歌曲列表, 那要提前准备好歌曲数据对吧

  • 为后续更新视图打下基础, 如果用户点击了操作, 让歌单的内容 +1 , 视图会自动更新

有状态和无状态的定义

有状态组件: 能定义state的组件, 类组件就是有状态组件

无状态组件: 不能定义state的组件, 函数组件又叫做无状态组件

注意2019年02月06日,rect 16.8中引入了 React Hooks,从而函数式组件也能定义自己的状态了

无状态组件的应用场景

  1. 组件本身就不需要有状态, 例如: 渲染一段固定的内容
  2. 组件本身就没有状态, 可以从外部传入

18. 类组件的状态

定义状态

固定格式, 使用 state = 对象 来做初始化

import React from 'react'

class Hello extends React.Component {
// 这里的state 就是状态
  state = {
    list: [{ id: 1, name: "明天会更好" },{ id: 2, name: "难忘今宵" }],
    isLoading: true
  }
  }
}

在视图中使用

import React from 'react'

class Hello extends React.Component {
// 这里的state 就是状态
  state = {
    list: [{ id: 1, name: "明天会更好" },{ id: 2, name: "难忘今宵" }],
    isLoading: true,
    count:2
  }
  }
  
  render () {
    return (
        <>
        <h1>歌单-{this.state.count}</h1>
        <ul>
          {this.state.list.map((item) => (
            <li key={item.id}>{item.name}</li>
          ))}
        </ul>
        <div>{this.state.isLoading ? "正在加载" : "加载完成"}</div>
      </>
    )
  }
}

19. 事件绑定

作用: 让页面有交互, 修改数据以更新视图

格式:

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

注意: react 事件名采用驼峰命名法, 必然要: onMouseEnter, onFocus, onClick…

示例

import React from 'react'
import ReactDOM from 'react-dom'

class Hello extends React.Component {
  fn () {
    console.log('触发了mouseEnter事件')
  }
  render () {
    return (
      <div>
        onClick={() => console.log('click事件被触发了')
        onMouseEnter={this.fn}
      </div>
    )
  }
}

ReactDOM.render(<Hello />,document.getElementById('root'))

注意:

  1. 事件名是小驼峰命名法格式

  2. 在类中补充方法

  3. this.fn 不要加括号:

    onClick={ this.fn() } 先调用fn() , 然后将 fn 的执行结果当做click事件的处理函数

  4. 别忘了写 this

20. 事件对象

react中, 通过事件处理函数的形参来获取

示例

hClick (e) {
  e.preventDefault()
  console.log('点击事件触发了',e)
}

render () {
  return (
    <div>
    <button onClick={(e) => console.log('按钮被点击了',e) }>按钮</button>
    <a href="http://www.baidu.com" onClick={ this.hClick }>百度</a>
    </div>
  )
}

21. 事件处理 - this指向问题

示例

class App extends React.Component {
  state = {
    msg: 'hello React!'
  }
  hClick () {
    console.log (this) // 这里的this是  undefined
  }
  render () {
    console.log (this) // 这里的this 是 实例对象
    return (
      <div>
        <button onClick={ this.hClick}>点击</button>
      </div>
    )
  }
}
  • render 方法中的 this 指向的是当前react组件
  • 事件处理程序中的this指向的是 `undefined

分析原因

  • 事件处理程序的函数式函数调用模式, 在严格模式下, this指向 undefined

  • render 函数是被组件实例调用的, 因此render函数中的 this 指向当前组件

class Person(name) {
  constructor(){
    this.name = name
  }
  say() {
    console.log(this)
  }
}
let p1 = new Person('小花')
p1.say() // this指向 p1 
const t = p1.say
t() // 指向 undefined

总结:

  1. class 的内部 , 开启了局部严格模式 use strict, this 不会指向 window ,所以输出 undefined

  2. onClick={ this.hClick}中, this.hClick的调用并不是通过类的实例调用, 所以值是 undefined

22. 事件处理 - this 指向解决方案

有三种方式

  1. Function.prototype.bind()
  2. 箭头函数
  3. class 的实例方法 [推荐]

方式一 - bind

class App extends React.Component {
  state = {
    msg: 'hello react!'
  }
  hClick () {
    console.log(this.state.msg)
  }
  redner () {
    return (
    <div>
      <button onClick={this.hClick.bind(this)}>按钮</button>
    </div>
    )
  }
}

方式二 - 箭头函数

class App extends React.Component {
  state = {
    msg: 'hello react!'
  }
  hClick () {
    console.log(this.state.msg)
  }
  redner () {
    return (
    <div>
      <button onClick={() => {this.hClick() }}>按钮</button>
    </div>
    )
  }
}

方式三 - 实例方法

class App extends React.Component {
  state = {
    msg: 'hello react'
  }

  handleClick = () => {
    console.log(this.state.msg)
  }
  render() {
    return (
      <div>
        <button onClick={this.handleClick}>点我</button>
      </div>
    )
  }
}

注意: 这个语法是实验性的语法 , 但是有babel的转义, 所有没有任何问题

23. 组件的状态 - 修改状态

语法: this.setState({要修改的部分数据})

作用: 修改 state , 更新 UI

示例

state = {
  num: 1
}
this.setState ({
  num : this.state.num + 1
})

理解状态不可变

  • react 核心理念是 状态不可变

  • 不要直接修改当前的状态值 , 而是创建新的状态值

这句话怎么理解呢 ? 我给你们写个示例就知道了

state = {
  num: 1
}
this.setState ({
  num : this.state.num + 1
})

就像这段代码, 可能有的人会想,为什么不使用++ 而是+ 1呢?

如果使用 ++ 那你可就报错了, 要牢牢记住这句话: 状态不可变

如果是++就立马执行了,改变了原先 num 的值 ,而+ 1 是公式,在这里并没有执行,

而是要等到触发才会执行 ,

重点: 不要修改 , 要赋值,用一个新的值来覆盖原先的值

24. setState的典型用法

使用场景:

state = {
  name: 'jack',
  assets: [{ id: 1, name: '手机' },{ id: 2, name: '耳机' }],
  skill: ['vue', 'react'], // angular
  info: {
    age: 18,
    city: '武汉'
  }
}

render () {
    const { name, assets, skill, info } = this.state
    return (
      <div>
        <h2>姓名:{name}</h2>
        <p>
          年龄:{info.age} 城市:{info.city}
        </p>
        <h3>资产</h3>
        <ul>{assets.map((item) => <li key={item.id}>{item.name}</li>)}</ul>
        <h3>技能</h3>
        <ul>{skill.map((item,idx) => <li key={idx}>{item}</li>)}</ul>
        <button
          onClick={() => {
            this.handleClick()
          }}>
          点我改数据
        </button>
      </div>
    )
  }

目的

  1. 把name 改成 ‘小花’
  2. 把 age 改成20
  3. 把 手机 改成电脑
  4. 向 skill 中 添加 angular
  5. 删除 id 为 2 的assets

参考答案

import { Component } from 'react'
import ReactDOM from 'react-dom'

class HelloReact extends Component {
  state = {
    name: 'jack',
    assets: [{ id: 1, name: '手机' }, { id: 2, name: '耳机' }],
    skill: ['vue', 'react'], // angular
    info: {
      age: 18,
      city: '武汉'
    }
  }

  hClick1 = () => {
    console.log(this.state.name)
    this.setState({
      name: '小花'
    })
  }

  hClick2 = () => {
    console.log(this.state.info.age)
    this.setState({
      info: {
        ...this.state.info,
        age: 20
      }
    })
  }

  hClick3 = () => {
    const newAssets = [...this.state.assets]
    newAssets[0].name = '电脑'
    this.setState({
      assets: newAssets
    })
  }

  hClick4= () => {
    this.setState({
      skill: [...this.state.skill, 'angular']
    })
  }

  hClick5= () => {
    const newAssets = this.state.assets.filter(item => item.id !== 2)
    this.setState({
      assets: newAssets
    })
  }

  render () {
    const { name, assets, skill, info } = this.state
    return (
      <div>
        <p>姓名:{name}</p>
        <p>
          age:{info.age}, city:{info.city}
        </p>
        <div>
          资产:<ul>{assets.map((item) => <li key={item.id}>{item.name}</li>)}</ul>
        </div>
        <p>skill:{skill.join(', ')}</p>
        <hr />
        {/*
        1. 把name改成'小花'
        2. 把age改成20
        3. 把'手机'改成'电脑'
        4. 向skill中添加'angular'
        5. 删除id为2的assets */}
        <button onClick={this.hClick1}>1. 把name改成小花</button>
        <button onClick={this.hClick2}>2. 把age改成20</button>
        <button onClick={this.hClick3}>3. 把手机改成电脑</button>
        <button onClick={this.hClick4}>4. 向skill中添加angular</button>
        <button onClick={this.hClick5}>5. 删除id为2的assets</button>
      </div>
    )
  }
}

const app = (
  <div>
    <HelloReact />
  </div>
)

ReactDOM.render(app, document.getElementById('root'))

25. 获取表单元素值的两种思路

class App extends React.Component {
  render() {
    return (
      <div>
        <h1>如何获取input中的值</h1>
        <p><input type="text" /></p>
        <button>点击按钮</button>
      </div>
    )
  }
}

思路

有两种思路:

  1. 直接找到表单元素进行dom操作 --> 非受控组件
  2. 将表单元素值与react的state绑定到一起,把用户的修改同步到state中。让组件受到react的控制–> 受控组件

26. 非受控组件 - ref

借助于 ref ,使用原生DOM 的方式来获取表单元素的值

ref 格式

步骤

  1. 导入方法。import { createRef } from 'react'
  2. 调用createRef方法创建引用,假设 名为refDom。 const refDom = createRef()
  3. refDom设置给表单元素的ref属性。<input ref={refDom}/>
  4. 通过refDom.current.value来获取值。console.log(this.refDom.current.value)

注:

  • 受控组件是通过 React 组件的状态来控制表单元素的值
  • 非受控组件是通过手动操作 DOM 的方式来控制
  • 此时,需要用到一个新的概念:ref
  • ref:用来在 React 中获取 DOM 元素

示例

import { createRef } from 'react'

class Hello extends Component {
// 调用方法创建引用
  txtRef = createRef()
  
  hClick = () => {
    console.log(this.txtRef.current.value)
  }
  render ({
    return (
      <div>
      	<h1>如何获取input中的值-非受控组件-ref</h1>
         {/*  设置给表单元素的ref属性 */}
        <p><input type="text" ref={this.txtRef}/></p>
        <button onClick={handleClick}>获取文本框的值</button>
      <div>
    )
  })

打印一下 : this.txtRef
在这里插入图片描述

27. 受控组件

如何理解受控

正常情况下,表单元素input是可任意输入内容的,可以理解为input自己维护它的状态(value)

受控组件的思路:

  1. 在state中定义状态
  2. 将state中的状态与表单元素的value值绑定到一起,进而通过state中的状态来控制表单元素的值 (类似vue中的双向绑定)

受控组件:value值受到了react控制的表单元素

实现步骤:

有两个步骤:

  1. 在state中定义状态

  2. 对表单元素做两件事

    1. 设置value为上面定义的状态
    2. 绑定onChange事件,并在回调中通过setState来修改状态值

    解释: 获取input的值 ,并赋值给 msg ,让input 的value绑定msg

class App extends React.Component {
  state = {
    // 1. 在state中定义状态
    msg: 'hello react'
  }

  handleChange = (e) => {
    this.setState({
      msg: e.target.value
    })
  }
  
  handleClick = ()=> {
    console.log(this.state.msg)
  }

  render() {
    return (
      <div>
        <p>
        {/* 2. 对表单元素做两件事 */}
          	<input type="text"
			 value={this.state.msg}
			 onChange={this.handleChange}
			/>
        </p>
        <button onClick={handleClick}>获取文本框的值</button>
      <div>
    )
  }
}

注意:

使用受控组件的方式处理表单元素后,状态的值就是表单元素的值。即:想要操作表单元素的值,只需要操作对应的状态即可

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值