组件化开发
将一个页面拆分成一个个小的功能块
组件的定义方式:**函数式组件**
和**类组件**
组件内部是否有状态需要维护: **无状态组件**
和**有状态组件**
组件职责:展示型组件和容器型组件
组件类型
类组件的定义要求:
- 必须以大写字符开头
- 继承自
**React.Component**
必须实现
**render**
函数,是唯一必须实现的方法import React, { Component } from "react";
class App extends Component {
render() {
return (
<div></div>
)
}
}
export default App;
函数式组件的要求:返回值和类组件中
render
函数返回一样的内容。函数式组件没有生命周期
- 没有内部状态
state
没有this指向组件实例
function App() {
return (
<div>
App
</div>
)
}
组件生命周期
组件从创建到销毁的整个过程,称之为组件的生命周期。
constructor: 初始化state或者绑定this实例
- render: 渲染JSX
- 挂载阶段:
**componentDidmount**
- DOM操作
- 网络请求
- 添加订阅
- 更新阶段:
**componentDidUpdate**
- 卸载阶段:
**componentWillUnmount**
getSnapshotBeforeUpdate() {
return {}
}
componentDidUpdate(prevProps,prevState,snapshot) {
}
组件通信
父传子
父组件通过**属性=值**
的形式来传递给子组件数据
子组件通过**props**
参数获取父组件传递的数据
<ChildCpns attr1={attr1} title="title标题"/>
const { attr1, title } = this.props
<Component {...obj}/>
参数propTypes
import PropTypes from 'prop-types'
ChildCpn.propTypes = {
name: PropTypes.string.isRequired,
}
// 指定props的默认值
ChildCpn.defaultProps = {
name: 'zzf'
}
class ChildCpn extends Component {
static defaultProps = {
name: 'zzf'
}
}
子传父
父组件给子组件传递一个回调函数,在子组件中调用这个函数。
import React, { Component } from 'react'
import AddCounter from './AddCounter'
export class App extends Component {
constructor() {
super()
this.state = {
counter: 100
}
}
changeCounter(count) {
this.setState({ counter: this.state.counter + count })
}
render() {
const { counter } = this.state
return (
<div>
<h2>当前计数: {counter}</h2>
<AddCounter addClick={(count) => this.changeCounter(count)}/>
</div>
)
}
}
export default App
import React, { Component } from 'react'
// import PropTypes from "prop-types"
export class AddCounter extends Component {
addCount(count) {
this.props.addClick(count)
}
render() {
return (
<div>
<button onClick={e => this.addCount(1)}>+1</button>
<button onClick={e => this.addCount(5)}>+5</button>
<button onClick={e => this.addCount(10)}>+10</button>
</div>
)
}
}
// AddCounter.propTypes = {
// addClick: PropTypes.func
// }
export default AddCounter
组件插槽
- 组件的
children
子元素 - 通过
props
传递 ```jsxleft
center
right
</Navbar
const { children } = this.props // 当传递多个元素时,children是一个数组 // 当传递一个元素时,children就是传递的元素
```jsx
<Navbar
leftSlot={<h2>left</h2>}
centerSlot={<h2>center</h2></h2>}
rightSlot={<h2>right</h2>}
/>
作用域插槽
通过回调函数返回内容来实现
<TabControl itemType={item => <button>{item}</button>} />
// TabControl.js,把该组件的item通过props传递给父组件
{this.props.itemType(item)}
非父子组件通信
Context
**Context**
提供了一种在组件之间共享值的方式,而不必逐层传递props
// 1. 创建一个context,并提供defaultValue
const ThemeContext = React.createContext({})
// 2. 通过Provider的value属性为后代组件传递数据
<ThemeContext.Provider value={{color: 'red'}}>
<Home/>
</ThemeContext.Provider>
// 3. 设置后代组件的contextType
HomeInfo.contextType = ThemeContext
// 4. 使用数据
console.log(this.context.color)
// 当为函数式组件或需要使用多个context时使用Context.Consumer
<ThemeContext.Consumer>
{
value => {
return <h2>{value.color}</h2>
}
}
</ThemeContext>
事件总线
// 引入自建库里封装的eventbus
import { HYEventBus } from 'hy-event-store'
const eventBus = new HYEventBus()
export default eventBus
eventBus.emit('eventName','zzf')
eventBus.on('eventName',cb)
eventBus.off('eventName',cb)
setState使用
必须通过**setState**
来告知React数据发生了变化
合并state
state = {
name: 'zzf',
age: 21
}
this.setState({
name: 'zdf'
})
Object.assign({name: 'zzf', age: 21}, { name: 'zdf'})
传入回调函数
this.setState((state, props) => {
// 1. 可以在回调函数中编写新的state的逻辑
// 2. 当前的回调函数会将之前的state和props传递进来
console.log(this.state.name} // 打印原来的state
// 返回state
return {
name: 'zdf'
}
})
异步调用
setState在React的事件处理中是一个异步调用 :::info setState设计为异步,可以显著的提升性能;
- 如果每次调用 setState都进行一次更新,那么意味着render函数会被频繁调用,界面重新渲染,这样效率是很低的;最好的办法应该是获取到多个更新,之后进行批量更新;
- 如果同步更新了state,但是还没有执行render函数,那么state和props(state中的数据传递给子组件的props)不能保持同步;state和props不能保持一致性,会在开发中产生很多的问题; ::: ```javascript this.setState({name: ‘zdf’}) console.log(this.state.name) // ‘zzf’
// 可以在setState中传入第二个参数:获取合并(更新)后的数据 this.setState({ name: ‘zdf’ },() => { console.log(this.state.name) // ‘zdf’ })
this.setState((state) => { return { counter: state.counter + 1 // 这里获取的也是更新后的数据 } })
<a name="zHFXQ"></a>
#### 同步的setState
React18之前,`setTimeout\Promise.then\原生DOM事件`是同步的
```javascript
// React18之前,获取的是同步结果
// React18之后,进行批处理,仍然是异步的
increment() {
setTimeout(() => {
this.setState({
counter: this.state.counter + 1
})
console.log(this.state.counter) // + 1后的结果
},0)
}
import { flushSync } from 'react-dom';
changeText() {
setTimeout(() => {
flushSync(() => {
this.setState({message: '要好好生活'})
})
console.log(this.state.message)
},0)
}