组件化开发
将一个页面拆分成一个个小的功能块
组件的定义方式:**函数式组件**和**类组件**
组件内部是否有状态需要维护: **无状态组件**和**有状态组件**
组件职责:展示型组件和容器型组件
组件类型
类组件的定义要求:
- 必须以大写字符开头
- 继承自
**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.statereturn (<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<NavbarleftSlot={<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,并提供defaultValueconst ThemeContext = React.createContext({})
// 2. 通过Provider的value属性为后代组件传递数据<ThemeContext.Provider value={{color: 'red'}}><Home/></ThemeContext.Provider>// 3. 设置后代组件的contextTypeHomeInfo.contextType = ThemeContext// 4. 使用数据console.log(this.context.color)
// 当为函数式组件或需要使用多个context时使用Context.Consumer<ThemeContext.Consumer>{value => {return <h2>{value.color}</h2>}}</ThemeContext>
事件总线
// 引入自建库里封装的eventbusimport { HYEventBus } from 'hy-event-store'const eventBus = new HYEventBus()export default eventBuseventBus.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// 返回statereturn {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>#### 同步的setStateReact18之前,`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)}
