React学习1

我会带着你远行 2023-10-03 11:47 59阅读 0赞

前言

最近做一个项目需要用到react,就开始学习一下react吧


目录

1.起步

2.安装脚手架

3.JSX 的基本使用

4.React组件

5.React 事件处理

事件绑定

事件对象

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

state的基本使用

setState的基本使用

7.this指向问题

1.箭头函数

2.Function.prototype.bind()

3.class的实例方法

8.表单处理

受控组件

  1. props

    组件通讯3种方式

    子传父

兄弟组件

props校验

10.Context

11.组件的生命周期

创建时

更新时

卸载时

12.render-props和高阶组件

render props模式

高阶组件

创建高阶组件

displayName

传递props


1.起步

1.React安装

  1. npm i react react-dom
  2. <div id="root"></div>
  3. <!-- 1 引入js文件 -->
  4. <script src="./node_modules/react/umd/react.development.js"></script>
  5. <script src="./node_modules/react-dom/umd/react-dom.development.js"></script>
  6. <script>
  7. // 2 创建react元素
  8. // 参数一:元素名称
  9. // 参数二:元素属性
  10. // 参数三:元素的子节点
  11. const title = React.createElement('h1', null, 'Hello React')
  12. // 3 渲染react元素
  13. // 参数一:要渲染的react元素
  14. // 参数二:挂载点
  15. ReactDOM.render(title, document.getElementById('root'))
  16. </script>

2.安装脚手架

  1. npx create-react-app my-app

导入react

  1. import React from 'react'
  2. import ReactDOM from 'react-dom'

3.JSX 的基本使用

JSX自动补全html标签

在这里插入图片描述

  1. const title = <h1>hello jsx</h1>

注意点

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70

JS表达式

  1. /*
  2. JSX中使用JavaScript表达式
  3. */
  4. const name = 'Jack'
  5. const age = 19
  6. const title = (
  7. <h1>
  8. Hello JSX, {name}, 年龄:{age}
  9. </h1>
  10. )

JSX中使用JavaScript表达式的注意点:

  1. import React from 'react'
  2. import ReactDOM from 'react-dom'
  3. /*
  4. JSX中使用JavaScript表达式的注意点:
  5. */
  6. // 函数调用表达式
  7. const sayHi = () => 'Hi~'
  8. const dv = <div>我是一个div</div>
  9. const title = (
  10. <h1>
  11. Hello JSX
  12. <p>{1}</p>
  13. <p>{'a'}</p>
  14. <p>{1 + 7}</p>
  15. <p>{3 > 5 ? '大于' : '小于等于'}</p>
  16. <p>{sayHi()}</p>
  17. {dv}
  18. {/* 错误演示 */}
  19. {/* <p>{ {a: '6'} }</p> */}
  20. {/* { if (true) {} } */}
  21. {/* { for (var i = 0; i < 10; i++) {} } */}
  22. </h1>
  23. )
  24. // 渲染react元素
  25. ReactDOM.render(title, document.getElementById('root'))

结果

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 1

条件渲染

  1. const isLoading = true
  2. // 逻辑与运算符:
  3. const loadData = () => {
  4. return isLoading && (<div>loading...</div>)
  5. }
  6. const title = (
  7. <h1>
  8. 条件渲染:
  9. {loadData()}
  10. </h1>
  11. )

20210725132840940.png

  1. const isLoading = true
  2. // if-else
  3. const loadData = () => {
  4. if (isLoading) {
  5. return <div>loading...</div>
  6. }
  7. return <div>数据加载完成,此处显示加载后的数据</div>
  8. }

20210725133023980.png

  1. const isLoading = false
  2. // 三元表达式:
  3. const loadData = () => {
  4. return isLoading ? (<div>loading...</div>) : (<div>数据加载完成,此处显示加载后的数据</div>)
  5. }

20210725133146151.png

列表渲染

  1. /*
  2. 列表渲染:
  3. */
  4. // 歌曲列表:
  5. const songs = [
  6. {id: 1, name: '痴心绝对'},
  7. {id: 2, name: '像我这样的人'},
  8. {id: 3, name: '南山南'},
  9. ]
  10. const list = (
  11. <ul>
  12. {songs.map(item => <li key={item.id}>{item.name}</li>)}
  13. </ul>
  14. )
  15. // 渲染react元素
  16. ReactDOM.render(list, document.getElementById('root'))

css

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 2

4.React组件

创建组件的两种方法

20210725195755666.png

函数组件

20210725200358677.png

20210725200405793.png

  1. const Hello=()=> <div>函数组件</div>
  2. // 渲染react元素
  3. ReactDOM.render(<Hello/>, document.getElementById('root'))

类组件

20210725200714125.png

  1. class Hello extends React.Component {
  2. render() {
  3. return (
  4. <div>第一个类组件</div>
  5. )
  6. }
  7. }
  8. // 渲染react元素
  9. ReactDOM.render(<Hello/>, document.getElementById('root'))

5.React 事件处理

事件绑定

20210725223053410.png

类组件事件绑定

  1. class App extends React.Component {
  2. // 事件处理程序
  3. handleClick() {
  4. console.log('单击事件触发了')
  5. }
  6. render() {
  7. return (
  8. <button onClick={this.handleClick}>点我,点我</button>
  9. )
  10. }
  11. }

函数组件事件绑定

  1. function App() {
  2. // 事件处理程序
  3. function handleClick() {
  4. console.log('函数组件中的事件绑定,事件触发了')
  5. }
  6. return (
  7. <button onClick={handleClick}>点我</button>
  8. )
  9. }

事件对象

20210725223459524.png

  1. class App extends React.Component {
  2. handleClick(e) {
  3. // 阻止浏览器的默认行为
  4. e.preventDefault()
  5. console.log('a标签的单击事件触发了')
  6. }
  7. render() {
  8. return (
  9. <a href="http://itcast.cn/" onClick={this.handleClick}>zjhhhhh</a>
  10. )
  11. }
  12. }

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

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 3

state的基本使用

20210725224437701.png

20210725224559128.png

  1. class App extends React.Component {
  2. /* constructor() {
  3. super()
  4. // 初始化state
  5. this.state = {
  6. count: 0
  7. }
  8. } */
  9. // (es6)简化语法初始化state(推荐)
  10. state = {
  11. count: 10
  12. }
  13. render() {
  14. return (
  15. <div>
  16. <h1>计数器:{ this.state.count }</h1>
  17. </div>
  18. )
  19. }
  20. }

setState的基本使用

  1. class App extends React.Component {
  2. state = {
  3. count: 0,
  4. test: 'a'
  5. }
  6. render() {
  7. return (
  8. <div>
  9. <h1>计数器:{ this.state.count }</h1>
  10. <button onClick={() => {
  11. this.setState({
  12. count: this.state.count + 1
  13. })
  14. // 错误!!!
  15. // this.state.count += 1
  16. }}>+1</button>
  17. </div>
  18. )
  19. }
  20. }

7.this指向问题

JSX中掺杂过多JS逻辑代码,会显得非常混乱,所以我们将逻辑抽离到单独的方法中,保证JSX 结构清晰

如下列代码

  1. class App extends React.Component {
  2. state = {
  3. count: 0
  4. }
  5. // 事件处理程序
  6. onIncrement() {
  7. console.log('事件处理程序中的this:', this)
  8. this.setState({
  9. count: this.state.count + 1
  10. })
  11. }
  12. render() {
  13. return (
  14. <div>
  15. <h1>计数器:{ this.state.count }</h1>
  16. <button onClick={this.onIncrement}>+1</button>
  17. {/* <button onClick={() => {
  18. this.setState({
  19. count: this.state.count + 1
  20. })
  21. }}>+1</button> */}
  22. </div>
  23. )
  24. }
  25. }

但是运行会报错

原因是事件处理程序中this的值为undefined,我们希望this指向组件实例(render方法的this即为组件实例)

有三种解决方法

1.箭头函数

20210725230226278.png

  1. class App extends React.Component {
  2. constructor() {
  3. super()
  4. this.state = {
  5. count: 0
  6. }
  7. this.onIncrement = this.onIncrement.bind(this)
  8. }
  9. // 事件处理程序
  10. onIncrement() {
  11. console.log('事件处理程序中的this:', this)
  12. this.setState({
  13. count: this.state.count + 1
  14. })
  15. }
  16. render() {
  17. return (
  18. <div>
  19. <h1>计数器:{ this.state.count }</h1>
  20. <button onClick={this.onIncrement}>+1</button>
  21. </div>
  22. )
  23. }
  24. }

2.Function.prototype.bind()

2021072523060688.png

  1. class App extends React.Component {
  2. constructor() {
  3. super()
  4. this.state = {
  5. count: 0
  6. }
  7. this.onIncrement = this.onIncrement.bind(this)
  8. }
  9. // 事件处理程序
  10. onIncrement() {
  11. console.log('事件处理程序中的this:', this)
  12. this.setState({
  13. count: this.state.count + 1
  14. })
  15. }
  16. render() {
  17. return (
  18. <div>
  19. <h1>计数器:{ this.state.count }</h1>
  20. <button onClick={this.onIncrement}>+1</button>
  21. </div>
  22. )
  23. }
  24. }

3.class的实例方法

20210725230908898.png

  1. class App extends React.Component {
  2. state = {
  3. count: 0
  4. }
  5. // 事件处理程序
  6. onIncrement = () => {
  7. console.log('事件处理程序中的this:', this)
  8. this.setState({
  9. count: this.state.count + 1
  10. })
  11. }
  12. render() {
  13. return (
  14. <div>
  15. <h1>计数器:{ this.state.count }</h1>
  16. <button onClick={this.onIncrement}>+1</button>
  17. </div>
  18. )
  19. }
  20. }

8.表单处理

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 4

受控组件" class="reference-link">watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 5 受控组件

  1. class App extends React.Component {
  2. state = {
  3. txt: ''
  4. }
  5. handleChange = e => {
  6. this.setState({
  7. txt: e.target.value
  8. })
  9. }
  10. render() {
  11. return (
  12. <div>
  13. <input type="text" value={this.state.txt} onChange={this.handleChange} />
  14. </div>
  15. )
  16. }
  17. }

20210725232029127.png

  1. class App extends React.Component {
  2. state = {
  3. txt: '',
  4. content: '',
  5. city: 'bj',
  6. isChecked: false
  7. }
  8. handleChange = e => {
  9. this.setState({
  10. txt: e.target.value
  11. })
  12. }
  13. // 处理富文本框的变化
  14. handleContent = e => {
  15. this.setState({
  16. content: e.target.value
  17. })
  18. }
  19. // 处理下拉框的变化
  20. handleCity = e => {
  21. this.setState({
  22. city: e.target.value
  23. })
  24. }
  25. // 处理复选框的变化
  26. handleChecked = e => {
  27. this.setState({
  28. isChecked: e.target.checked
  29. })
  30. }
  31. render() {
  32. return (
  33. <div>
  34. {/* 文本框 */}
  35. <input type="text" value={this.state.txt} onChange={this.handleChange} />
  36. <br/>
  37. {/* 富文本框 */}
  38. <textarea value={this.state.content} onChange={this.handleContent}></textarea>
  39. <br/>
  40. {/* 下拉框 */}
  41. <select value={this.state.city} onChange={this.handleCity}>
  42. <option value="sh">上海</option>
  43. <option value="bj">北京</option>
  44. <option value="gz">广州</option>
  45. </select>
  46. <br/>
  47. {/* 复选框 */}
  48. <input type="checkbox" checked={this.state.isChecked} onChange={this.handleChecked} />
  49. </div>
  50. )
  51. }
  52. }

多表单元素的优化

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 6

  1. class App extends React.Component {
  2. state = {
  3. txt: '',
  4. content: '',
  5. city: 'bj',
  6. isChecked: false
  7. }
  8. handleForm = e => {
  9. // 获取当前DOM对象
  10. const target = e.target
  11. // 根据类型获取值
  12. const value = target.type === 'checkbox'
  13. ? target.checked
  14. : target.value
  15. // 获取name
  16. const name = target.name
  17. this.setState({
  18. [name]: value
  19. })
  20. }
  21. render() {
  22. return (
  23. <div>
  24. {/* 文本框 */}
  25. <input type="text" name="txt" value={this.state.txt} onChange={this.handleForm} />
  26. <br/>
  27. {/* 富文本框 */}
  28. <textarea name="content" value={this.state.content} onChange={this.handleForm}></textarea>
  29. <br/>
  30. {/* 下拉框 */}
  31. <select name="city" value={this.state.city} onChange={this.handleForm}>
  32. <option value="sh">上海</option>
  33. <option value="bj">北京</option>
  34. <option value="gz">广州</option>
  35. </select>
  36. <br/>
  37. {/* 复选框 */}
  38. <input type="checkbox" name="isChecked" checked={this.state.isChecked} onChange={this.handleForm} />
  39. </div>
  40. )
  41. }
  42. }

非受控组件

20210725233037109.png

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 7

  1. class App extends React.Component {
  2. constructor() {
  3. super()
  4. this.txtRef=React.createRef()
  5. }
  6. gettxt=()=> {
  7. console.log('文本框的值为:',this.txtRef.current.value);
  8. }
  9. render() {
  10. return (
  11. <div>
  12. <input type="text" ref={this.txtRef}/>
  13. <button onClick={this.gettxt}>获取文本框的值</button>
  14. </div>
  15. )
  16. }
  17. }

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 8

9. props

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 9

  1. const Hello = props => {
  2. console.log('props:', props)
  3. props.fn()
  4. return (
  5. <div>
  6. <h1>props:</h1>
  7. {props.tag}
  8. </div>
  9. )
  10. }
  11. ReactDOM.render(
  12. <Hello
  13. name="rose"
  14. age={19}
  15. colors={['red', 'green', 'blue']}
  16. fn={() => console.log('这是一个函数')}
  17. tag={<p>这是一个p标签</p>}
  18. />,
  19. document.getElementById('root')
  20. )

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 10

组件通讯3种方式" class="reference-link">watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 11 组件通讯3种方式

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 12

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 13

子传父

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 14

  1. class Parent extends React.Component {
  2. state = {
  3. parentMsg: ''
  4. }
  5. // 提供回调函数,用来接收数据
  6. getChildMsg = data => {
  7. console.log('接收到子组件中传递过来的数据:', data)
  8. this.setState({
  9. parentMsg: data
  10. })
  11. }
  12. render() {
  13. return (
  14. <div className="parent">
  15. 父组件:{this.state.parentMsg}
  16. <Child getMsg={this.getChildMsg} />
  17. </div>
  18. )
  19. }
  20. }
  21. // 子组件
  22. class Child extends React.Component {
  23. state = {
  24. msg: '刷抖音'
  25. }
  26. handleClick = () => {
  27. // 子组件调用父组件中传递过来的回调函数
  28. this.props.getMsg(this.state.msg)
  29. }
  30. render() {
  31. return (
  32. <div className="child">
  33. 子组件:{' '}
  34. <button onClick={this.handleClick}>点我,给父组件传递数据</button>
  35. </div>
  36. )
  37. }
  38. }
  39. ReactDOM.render(<Parent />, document.getElementById('root'))

兄弟组件

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 15

  1. // 父组件
  2. class Counter extends React.Component {
  3. // 提供共享状态
  4. state = {
  5. count: 0
  6. }
  7. // 提供修改状态的方法
  8. onIncrement = () => {
  9. this.setState({
  10. count: this.state.count + 1
  11. })
  12. }
  13. render() {
  14. return (
  15. <div>
  16. <Child1 count={this.state.count} />
  17. <Child2 onIncrement={this.onIncrement} />
  18. </div>
  19. )
  20. }
  21. }
  22. const Child1 = props => {
  23. return <h1>计数器:{props.count}</h1>
  24. }
  25. const Child2 = props => {
  26. return <button onClick={() => props.onIncrement()}>+1</button>
  27. }
  28. ReactDOM.render(<Counter />, document.getElementById('root'))

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 16

props校验

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 17 watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 18

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 19

安装prop-types

  1. npm i prop-types

props默认值

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 20

10.Context

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 21

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 22

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 23

步骤

(1) 创建context得到两个组件

  1. const { Provider, Consumer } = React.createContext()

(2)用Provider组件包裹根组件(value代表要传的值)

  1. class App extends React.Component {
  2. render() {
  3. return (
  4. <Provider value="pink">
  5. <div className="app">
  6. <Node />
  7. </div>
  8. </Provider>
  9. )
  10. }
  11. }

(3)目标子组件包裹要Consumer组件 (data就是传过来的值, {data}在标签中渲染data)

  1. const Child = props => {
  2. return (
  3. <div className="child">
  4. <Consumer>{data => <span>我是子节点 -- {data}</span>}</Consumer>
  5. </div>
  6. )
  7. }

2021072821235017.png

11.组件的生命周期

20210728232003470.pngwatermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 24

创建时

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 25

更新时

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 26

setState和forceUpdate()

  1. class App extends React.Component {
  2. constructor(props) {
  3. super(props)
  4. // 初始化state
  5. this.state = {
  6. count: 0
  7. }
  8. }
  9. // 打豆豆
  10. handleClick = () => {
  11. this.setState({
  12. count: this.state.count + 1
  13. }) }
  14. render() {
  15. console.warn('生命周期钩子函数: render')
  16. return (
  17. <div>
  18. <Counter count={this.state.count} />
  19. <button onClick={this.handleClick}>打豆豆</button>
  20. </div>
  21. )
  22. }
  23. }
  24. class Counter extends React.Component {
  25. render() {
  26. console.warn('--子组件--生命周期钩子函数: render')
  27. return <h1>统计豆豆被打的次数:{this.props.count}</h1>
  28. }
  29. }

20210729000735252.png

强制更新

  1. // 演示强制更新:
  2. this.forceUpdate()
  3. class Counter extends React.Component {
  4. render() {
  5. console.warn('--子组件--生命周期钩子函数: render')
  6. return <h1 id="title">统计豆豆被打的次数:{this.props.count}</h1>
  7. }
  8. // 注意:如果要调用 setState() 更新状态,必须要放在一个 if 条件中
  9. // 因为:如果直接调用 setState() 更新状态,也会导致递归更新!!!
  10. componentDidUpdate(prevProps) {
  11. console.warn('--子组件--生命周期钩子函数: componentDidUpdate')
  12. // 正确做法:
  13. // 做法:比较更新前后的props是否相同,来决定是否重新渲染组件
  14. console.log('上一次的props:', prevProps, ', 当前的props:', this.props)
  15. if (prevProps.count !== this.props.count) {
  16. this.setState({})
  17. // 发送ajax请求的代码
  18. }
  19. // 错误演示!!!
  20. // this.setState({})
  21. // 获取DOM
  22. // const title = document.getElementById('title')
  23. // console.log(title.innerHTML)
  24. }
  25. }

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 27

卸载时

20210729002759831.png

  1. class Counter extends React.Component {
  2. componentDidMount() {
  3. // 开启定时器
  4. this.timerId = setInterval(() => {
  5. console.log('定时器正在执行~')
  6. }, 500)
  7. }
  8. render() {
  9. return <h1>统计豆豆被打的次数:{this.props.count}</h1>
  10. }
  11. componentWillUnmount() {
  12. console.warn('生命周期钩子函数: componentWillUnmount')
  13. // 清理定时器
  14. clearInterval(this.timerId)
  15. }
  16. }

12.render-props和高阶组件

render props模式" class="reference-link">watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 28 render props模式

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 29

  1. class Mouse extends React.Component {
  2. // 鼠标位置state
  3. state = {
  4. x: 0,
  5. y: 0
  6. }
  7. // 鼠标移动事件的事件处理程序
  8. handleMouseMove = e => {
  9. this.setState({
  10. x: e.clientX,
  11. y: e.clientY
  12. })
  13. }
  14. // 监听鼠标移动事件
  15. componentDidMount() {
  16. window.addEventListener('mousemove', this.handleMouseMove)
  17. }
  18. render() {
  19. // return null
  20. return this.props.render(this.state)
  21. }
  22. }
  23. class App extends React.Component {
  24. render() {
  25. return (
  26. <div>
  27. <h1>render props 模式</h1>
  28. <Mouse
  29. render={mouse => {
  30. return (
  31. <p>
  32. 鼠标位置:{mouse.x} {mouse.y}
  33. </p>
  34. )
  35. }}
  36. />
  37. </div>
  38. )
  39. }
  40. }

把鼠标变成一只猫

  1. <Mouse
  2. render={mouse => {
  3. return (
  4. <img
  5. src={img}
  6. alt="猫"
  7. style={
  8. {
  9. position: 'absolute',
  10. top: mouse.y - 64,
  11. left: mouse.x - 64
  12. }}
  13. />
  14. )
  15. }}
  16. />
  17. </div>
  18. )
  19. }
  20. }

更推荐用children属性代替render属性,即在Mouse组件嵌套一个子节点

20210730132053909.png

  1. <Mouse>
  2. {mouse => (
  3. <img
  4. src={img}
  5. alt="猫"
  6. style={
  7. {
  8. position: 'absolute',
  9. top: mouse.y - 64,
  10. left: mouse.x - 64
  11. }}
  12. />
  13. )}
  14. </Mouse>

组件中的render函数也要改变

  1. render() {
  2. return this.props.children(this.state)
  3. }

代码优化

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 30

高阶组件

20210730132920564.png

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 31 watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 32

创建高阶组件" class="reference-link">20210730133940351.png 创建高阶组件

  1. // 创建高阶组件
  2. function withMouse(WrappedComponent) {
  3. // 该组件提供复用的状态逻辑
  4. class Mouse extends React.Component {
  5. // 鼠标状态
  6. state = {
  7. x: 0,
  8. y: 0
  9. }
  10. handleMouseMove = e => {
  11. this.setState({
  12. x: e.clientX,
  13. y: e.clientY
  14. })
  15. }
  16. // 控制鼠标状态的逻辑
  17. componentDidMount() {
  18. window.addEventListener('mousemove', this.handleMouseMove)
  19. }
  20. componentWillUnmount() {
  21. window.removeEventListener('mousemove', this.handleMouseMove)
  22. }
  23. render() {
  24. return <WrappedComponent {...this.state} />
  25. }
  26. }
  27. return Mouse
  28. }

包装组件

  1. const Position = props => (
  2. <p>
  3. 鼠标当前位置:(x: {props.x}, y: {props.y})
  4. </p>
  5. )
  6. // 猫捉老鼠的组件:
  7. const Cat = props => (
  8. <img
  9. src={img}
  10. alt=""
  11. style={
  12. {
  13. position: 'absolute',
  14. top: props.y - 64,
  15. left: props.x - 64
  16. }}
  17. />
  18. )
  19. // 获取增强后的组件:
  20. const MousePosition = withMouse(Position)
  21. // 调用高阶组件来增强猫捉老鼠的组件:
  22. const MouseCat = withMouse(Cat)

渲染包装后的组件

  1. class App extends React.Component {
  2. render() {
  3. return (
  4. <div>
  5. <h1>高阶组件</h1>
  6. {/* 渲染增强后的组件 */}
  7. <MousePosition />
  8. <MouseCat />
  9. </div>
  10. )
  11. }
  12. }

displayName

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 33

  1. // 创建高阶组件
  2. function withMouse(WrappedComponent) {
  3. // 该组件提供复用的状态逻辑
  4. class Mouse extends React.Component {
  5. // 鼠标状态
  6. state = {
  7. x: 0,
  8. y: 0
  9. }
  10. handleMouseMove = e => {
  11. this.setState({
  12. x: e.clientX,
  13. y: e.clientY
  14. })
  15. }
  16. // 控制鼠标状态的逻辑
  17. componentDidMount() {
  18. window.addEventListener('mousemove', this.handleMouseMove)
  19. }
  20. componentWillUnmount() {
  21. window.removeEventListener('mousemove', this.handleMouseMove)
  22. }
  23. render() {
  24. return <WrappedComponent {...this.state} />
  25. }
  26. }
  27. // 设置displayName
  28. Mouse.displayName = `WithMouse${getDisplayName(WrappedComponent)}`
  29. return Mouse
  30. }
  31. function getDisplayName(WrappedComponent) {
  32. return WrappedComponent.displayName || WrappedComponent.name || 'Component'
  33. }

20210730143355129.png

传递props

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FfRF9IX0VfUl9F_size_16_color_FFFFFF_t_70 34

  1. const MousePosition = withMouse(Position)

往被包装的组件传递props,这时被包装的组件拿不到这个props

  1. <MousePosition a="1" />

需要高阶组件传给他

  1. render() {
  2. console.log('Mouse:', this.props)
  3. return <WrappedComponent {...this.state} {...this.props} />
  4. }

发表评论

表情:
评论列表 (有 0 条评论,59人围观)

还没有评论,来说两句吧...

相关阅读

    相关 React学习(1)-create-react-app

    前言 如今,对于现今前端热门的三大框架Vue,Angular,React,对于web开发者来说,早已不是什么陌生的词 尽管三者实现业务最终的目的都能达成一致,但是各...

    相关 react学习之路1

    公司使用的react,但自身基本不了解,这是我要学习react的目的之一。(还要对es6,typescript了解) 在阅读了一些基础知识之后,我想要边实战边学习,实战才是真