02-component
1. 概念
一个组件就是一个用户界面的一部分,它可以有自己的逻辑和外观,组件之间可以互相嵌套,也可以服用多次
2. 基础使用
在React中,一个组件就是首字母大写的函数,内部存放了组件的逻辑和视图UI, 渲染组件只需要把组件当成标签书写即可
// 1. 定义组件
function Button() {
return <button>click me</button>
}
// 2. 使用组件
function App() {
return (
<div>
{/* 自闭和 */}
<Button/>
{/* 成对标签 */}
<Button></Button>
</div>
)
}
2. 状态管理
1. 基础使用
useState 是一个 React Hook(函数),它允许我们向组件添加一个
状态变量
,从而控制影响组件的渲染结果和普通 JS 变量不同的是,状态变量一旦发生变化组件的视图 UI 也会跟着变化(数据驱动视图)
import React from "react";
function App() {
const [count, setCount] = React.useState(0)
return (
<div>
<button onClick={() => setCount(count + 1)}>{count}</button>
</div>
)
}
2. 状态的修改规则
在 React 中状态被认为是只读的,应该始终
替换它而不是修改它
,直接修改状态不能引发视图更新
function App() {
let [count, setCount] = React.useState(0)
const handleClick = () => {
// 直接修改,无法引发视图更新
count++;
console.log(count)
}
return (
<div>
<button onClick={handleClick}>{count}</button>
</div>
)
}
function App() {
let [count, setCount] = React.useState(0)
const handleClick = () => {
// 作用:
// 1. 用传入的新值修改 count
// 2. 重新使用新的 count 渲染 UI
setCount(count + 1)
}
return (
<div>
<button onClick={handleClick}>{count}</button>
</div>
)
}
3. 修改对象状态
对于对象类型的状态变量,应该始终给
setter()
一个全新的对象
来进行修改
import React, {useState} from "react";
function App() {
const [form, setForm] = useState({
name: 'jack',
})
const handleChangeName = () => {
// 直接修改原对象,不引发视图变化
form.name = 'john'
}
return (
<div>
<button onClick={handleChangeName}>{form.name}</button>
</div>
)
}
import React, {useState} from "react";
function App() {
const [form, setForm] = useState({
name: 'jack',
})
const handleChangeName = () => {
// 调用 set 传入新对象用于修改
setForm({
...form,
name: 'john',
})
}
return (
<div>
<button onClick={handleChangeName}>{form.name}</button>
</div>
)
}
3. 基础样式处理
React 组件基础的样式控制有两种方式,行内样式、class 类名控制
function App() {
return (
<div>
<div style={{color: 'red'}}>this is div</div>
</div>
)
}
const ooxx = {
color: 'red'
}
function App() {
return (
<div>
<div style={ooxx}>this is div</div>
</div>
)
}
.foo {
color: red;
}
import './index.css'
function App(){
return (
<div>
<span className="foo">this is span</span>
</div>
)
}
4. 自增组件
Counter 自增组件,看一下组件的基础编写结构
import {Component} from 'react'
class Counter extends Component {
// 状态变量
state = {
count: 0,
}
// 事件回调
clickHandler = () => {
// 修改状态变量,触发 UI 组件渲染
this.setState({
count: this.state.count + 1,
})
}
// UI模版
render() {
return <button onClick={this.clickHandler}>+{this.state.count}</button>
}
}
function App() {
return (
<div>
<Counter/>
</div>
)
}
export default App
5. 生命周期
概念:组件从创建到销毁的各个阶段自动执行的函数就是生命周期函数
componentDidMount
:组件挂载完毕自动执行 —— 异步数据获取componentWillUnmount
:组件卸载时自动执行 —— 清理副作用
6. 组件通信
概念:组件通信就是
组件之间的数据传递
,根据组件嵌套关系的不同,有不同的通信手段和方法
- A-B:父子通信
- B-C:兄弟通信
- A-E:跨层通信
1. 父传子
1. 基础实现
- 父组件传递数据:在子组件标签上绑定属性
- 子组件接收数据:子组件通过props参数接收数据
function Son(props) {
return <div>{props.name}</div>
}
function App() {
const name = 'this is app name'
return (
<div>
<Son name={name}/>
</div>
)
}
import {Component} from 'react'
class Son extends Component {
render() {
const {count} = this.props
return <div>this is Son, {count}</div>
}
}
class App extends Component {
// 状态变量
state = {
count: 0,
}
setCount = () => {
this.setState({
count: this.state.count + 1,
})
}
// UI 模版
render() {
return (
<>
<Son count={this.state.count}/>
<button onClick={this.setCount}>+</button>
</>
)
}
}
export default App
2. props说明
props 可以传递任意的合法数据。props 是只读对象
- 数字
- 字符串
- 布尔值
- 数组
- 对象
- 函数
- JSX
function Son(props) {
console.log(props)
return <div>{props.name}</div>
}
const appName = 'this is app name';
function App() {
const name = 'this is app name'
return (
<div>
<Son
name={appName}
age={20}
isTrue={false}
list={['Vue', 'React']}
obj={{name: 'jack'}}
cb={() => console.log(123)}
child={<span>this is span child</span>}
/>
</div>
)
}
3. 特殊prop-children
场景:当把内容嵌套在组件的标签内部时,组件会自动在名为 children 的 prop 属性中接收该内容
2. 子传父
核心思路:在子组件中,调用父组件中的函数并传递参数
function Son({onGetMsg}) {
const sonMsg = 'this is son msg'
return (
<div>
{/* 在子组件中执行父组件传递过来的函数 */}
<button onClick={() => onGetMsg(sonMsg)}>send</button>
</div>
)
}
function App() {
const getMsg = (msg) => console.log(msg)
return (
<div>
{/* 传递父组件中的函数到子组件 */}
<Son onGetMsg={getMsg}/>
</div>
)
}
import {Component} from 'react'
class Son extends Component {
render() {
const {msg, onGetSonMsg} = this.props
return (
<>
<div>this is Son, {msg}</div>
<button onClick={() => onGetSonMsg('this is son msg')}>
changeMsg
</button>
</>
)
}
}
class App extends Component {
// 状态变量
state = {
msg: 'this is initail app msg',
}
onGetSonMsg = (msg) => {
this.setState({msg})
}
// UI 模版
render() {
return (
<>
<Son msg={this.state.msg} onGetSonMsg={this.onGetSonMsg}/>
</>
)
}
}
export default App
3. 兄弟组件
实现思路:借助
状态提升
机制,通过共同的父组件进行兄弟之间的数据传递
- 通过子传父:A -> App
- 通过父传子:App -> B
import {useState} from 'react'
function A({onGetAName}) {
// Son 组件中的数据
const name = 'A.msg'
return (
<div>
this is A component =>
<button onClick={() => onGetAName(name)}>send</button>
</div>
)
}
function B({name}) {
return (
<div>
this is B component => receive =>
{name}
</div>
)
}
function App() {
const [name, setName] = useState('')
const getAName = (name) => {
setName(name)
}
return (
<div>
this is App
<A onGetAName={getAName}/>
<B name={name}/>
</div>
)
}
export default App
4. 跨层组件
- 使用
createContext()
创建一个上下文对象 Ctx - 在顶层组件(App)中通过
Ctx.Provider
组件提供数据 - 在底层组件(B)中通过
useContext
钩子函数获取消费数据 App -> A -> B
import {createContext, useContext} from "react"
// 1. createContext() 创建一个上下文对象
const MsgContext = createContext()
function A() {
return (
<div>
this is A component
<B/>
</div>
)
}
function B() {
// 3. 在底层组件。通过 useContext 钩子函数使用数据
const msg = useContext(MsgContext)
return (
<div>
this is B component => {msg}
</div>
)
}
function App() {
const msg = 'this is app msg'
return (
<div>
{/* 2. 在顶层组件。通过 Provider 组件提供数据 */}
<MsgContext.Provider value={msg}>
this is App
<A/>
</MsgContext.Provider>
</div>
)
}
export default App