1.组件介绍
- * 组件是 React 开发(现代前端开发)中最重要的内容
- * 组件允许你将 UI 拆分为独立、可复用的部分,每个部分都可以独立的思考
- * 组合多个组件(组装乐高积木)实现完整的页面功能
- * 特点:独立、可复用、可组合
- * 组件包含三部分:HTML/CSS/JS
- * 展示页面中的可复用部分
2.创建组件---函数组件
- 函数组件:使用JS的函数或者箭头函数创建的组件
* 使用 JS 的函数(或箭头函数)创建的组件,叫做`函数组件`
* 约定1:函数名称必须以大写字母开头,区分组件和普通的 HTML标签
* 约定2:函数组件必须有返回值,表示该组件的 UI 结构;如果不需要渲染任何内 容,则返回 `null`
- 使用函数创建组件
// 使用普通函数创建组件:
function Hello() {
return <div>这是我的第一个函数组件!</div>
}
function Button() {
return <button>按钮</button>
}
// 使用箭头函数创建组件:
const Hello = () => <div>这是我的第一个函数组件!</div>
- 使用组件
* 组件就像 HTML 标签一样可以被渲染到页面中。组件表示的是一段结构内容,对于函数组件来说,渲染的内容是函数返回值对应的内容
* 使用函数名称作为组件标签名称
// 使用 双标签 渲染组件:
<Hello></Hello>
ReactDOM.render(<Hello></Hello>, root)
// 使用 单标签 渲染组件:
<Hello />
ReactDOM.render(<Hello />, root)
**小结**:
1. 在react中可以使用函数或者箭头函数创建组件
2. 组件的首字母必须大写
3.创建组件---类组件
- 内容
* 使用 ES6 的 class 创建的组件,叫做类(class)组件
* 约定1:**类名称也必须以大写字母开头**
* 约定2:类组件应该继承 React.Component 父类,从而使用父类中提供的方法或属性
* 约定3:类组件必须提供 render 方法
* 约定4:render 方法必须有返回值,表示该组件的 UI 结构
- 定义组件
// 导入 React
import React from 'react'
class Hello extends React.Component {
render() {
return <div>Hello Class Component!</div>
}
}
ReactDOM.render(<Hello />, root)
// 只导入 Component
import { Component } from 'react'
class Hello extends Component {
render() {
return <div>Hello Class Component!</div>
}
}
- 使用组件
ReactDOM.render(<Hello />, root)
4.将组件提取到单独的js中
// index.js
import Hello from './Hello'
// 渲染导入的Hello组件
ReactDOM.render(<Hello />, root)
// Hello.js
import { Component } from 'react'
class Hello extends Component {
render() {
return <div>Hello Class Component!</div>
}
}
// 导出Hello组件
export default Hello
导出:export default
导入:import
5.有状态组件和无状态组件
- 函数组件又叫做*无状态组件* ,函数组件是不能自己提供响应数据
- 类组件又叫做*有状态组件* ,类组件可以**自己提供数据**
- **状态(state)**是组件的私有数据,当组件的状态发生了改变,页面结构也就发生了改变 (**数据驱动视图**)
- **函数组件是没有状态的,只负责页面的展示**(`静`态,不会发生变化),性能比较高
- **类组件有自己的状态,负责*更新UI*,只要类组件的数据发生了改变,UI 就会发生更新**(` 动`态)
- 在项目中,一般都是由函数组件和类组件共同配合来完成的
比如计数器案例,点击按钮让数值+1, 0和1就是不同时刻的状态,当状态从0变成1之后,UI也要跟着发生变化。React想要实现这种功能,就需要使用有状态组件来完成。
6.类组件的状态
- * 状态`state`,即数据,是组件内部的**私有数据**,只能在组件内部使用
- * 状态 state 的值是**对象**,表示一个组件中可以有多个数据
- * 通过 `this.state.xxx` 来获取状态
创建
class Hello extends Component {
// 为组件提供状态
state = {
count: 0,
list: [],
isLoading: true
}
render() {
return (
<div>计数器</div>
)
}
}
读取
class Hello extends Component {
// ...
render() {
// 通过 this.state 来访问类组件的状态
return (
<div>计数器:{this.state.count}</div>
)
}
}
对象不能直接显示
7.事件处理----注册事件
- * React注册事件与DOM的事件语法非常像
- * 语法`on+事件名 ={事件处理程序}` 比如`onClick={this.handleClick}`
- * 注意:*React事件采用驼峰命名法*,比如`onMouseEnter`, `onClick`
import React, { Component } from 'react' // 函数组件(没有组件实例,不能使用this) function Fn(props) { // 点击事件 回调函数 e=>事件对象 const handleClick=(e)=>{ console.log('123',e); } return ( <div> <h1>函数组件</h1> <button onClick={handleClick}>点击</button> </div> ) } // export default Fn; // 类组件 export default class 事件绑定 extends Component { // 点击事件 回调函数 e=>事件对象 handleClick(e){ console.log('123',e.target); } // 阻止跳转 go(e){ e.preventDefault() } render() { return ( <div> <h1>事件绑定</h1> <p> <a onClick={this.go} href="http://www.baidu.com">baidu</a> </p> {/* 点击调用 */} <button onClick={this.handleClick}>点击</button> </div> ) } }
rcc-》类组件快速创建 rsf-》函数组件快速创建 e.target-》触发的对象 e.prevenDefault()-》阻止跳转 函数组件(没有组件实例,不能使用this)
8.setState 修改状态
- * 语法:this.setState({ 要修改的部分数据 })
- * setState() 作用:1 **修改 state** 2 **更新 UI**
- * 思想:**数据驱动视图**,也就是只需要修改数据(状态)那么页面(视图)就会自动刷新
- * 核心:数据!!!
- * 从现在开始,我们关心的是如何修改数据,而不再是关心如何修改DOM
- * 并且,注意:尽量避免直接手动 DOM(通过 document.querySelector() 获取到到DOM对 象然后再操作) 操作!!!
- *不要直接修改 state 中的值,这是无效的!例如this.state.count++, this.state.arr.push()等
import React, { Component } from 'react'
// 类组件
export default class 事件绑定 extends Component {
state={
count:1,
str:'2'
}
// 点击事件 回调函数 e=>事件对象
handleClick=()=>{
this.setState({
count: this.state.count+1,
str:Math.random()*100+''
})
}
render() {
return (
<div>
{/* 点击调用 */}
<div>{this.state.count}</div>
<div>{this.state.str}</div>
<button onClick={this.handleClick}>点击</button>
</div>
)
}
}
总结**:
1. 能直接修改 state 的值吗?不能
2. 如何修改 React 组件中的状态?`setState()`
3. setState 是哪来的?从 Component 父类继承过来的,所以在类组件使用
9.react核心理念-状态不可变
- 状态不可变指的是:不要直接修改状态的值,而是基于当前状态创建新的状态值
state = {
count: 0,
list: [1, 2, 3],
person: {
name: 'jack',
age: 18
}
}
// 【不推荐】直接修改当前值的操作:
this.state.count++
++this.state.count
this.state.count += 1
this.state.count = 1
// 只要是数组中直接修改当前数组的方法都不能用!
this.state.list.push(123)
this.state.person.name = 'rose'
// 【推荐】不是直接修改当前值,而是创建新值的操作:
this.setState({
count: this.state.count + 1,
list: [...this.state.list, 123],
person: {
...this.state.person,
// 要修改的属性,会覆盖原来的属性,这样,就可以达到修改对象中属性的目的了
name: 'rose'
}
})
10.表单处理-受控组件
目标:能够使用受控组件的方式获取文本框的值========= vue表单开发:v-modle 双向绑定
- HTML中表单元素是可输入的,即表单元素维护着自己的可变状态(value)
- 但是在react中,可变状态通常是保存在`state`中的,且要求状态只能通过`setState`进行修改
- React中将state中的数据与表单元素的value值绑定在一起,由state的值来控制表单元素的值
- 受控组件:value值受到了react状态控制的表单元素
代码实例
import React, { Component } from 'react'
export default class App extends Component {
state={
val:'11'
}
// 点击提交按钮方法
handleClick=()=>{
console.log(this.state.val);
}
// input输入框值改变触发
handleChange=(e)=>{
this.setState({
val:e.target.value
})
}
render() {
return (
<div>
<h1>受控组件 (双向绑定)</h1>
<input type="text" value={this.state.val} onChange={this.handleChange}/>
<button style={{'margin-left':10}} onClick={this.handleClick}>提交</button>
</div>
)
}
}
rcc----快速创建类组件
11.表单处理-非受控组件
**非受控组件借助于ref,使用原生DOM的方式来获取表单元素的值
- 受控组件是通过 React 组件的状态来控制表单元素的值
- 非受控组件是通过**手动操作 DOM 的**方式来控制
- 此时,需要用到一个新的概念:`ref`
- ref:用来在 React 中获取 DOM 元素
- 函数组件没有实例,不要绑定ref
import React, { Component, createRef } from 'react' class Child extends Component{ render(){ return ( <div> <h3>我是子组件</h3> </div> ) } } export default class FeiShou extends Component { // 创建ref对象,获取dom对象 input=createRef() // 创建ref对象,获取组件实例 child=createRef() // 获取input getInput=()=>{ console.log('input',this.input.current.value); } // 获取子组件实例 getChild=()=>{ console.log('input',this.child); } render() { return ( <div> <h1>非受控组件</h1> {/* 将ref绑定到input */} <input ref={this.input} type="text" /> <button onClick={this.getInput}>获取input元素dom对象</button> <hr /> <Child ref={this.child}/> <button onClick={this.getChild}>获取子组件</button> </div> ) } }