React框架学习(二)

本文围绕React展开,介绍了setState更新状态的正确写法,组件通讯的多种方式,包括父子、兄弟和跨组件通讯。还阐述了React生命周期的三个阶段及各阶段触发的钩子函数,如挂载期的constructor、render等。最后讲解了setState的进阶用法,如延迟更新、立即生效及同步异步情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一丶setState更新状态

this.stState基于当前值更新UI状态,不能使用this.state.count += 1 或  ++ 的写法

import { Component } from 'react'

export default class App extends Component {
  // 提供状态
  state = {
    count: 0
  }

  // 事件处理程序
  handleClick = () => {
    // 更新状态 10
    // this.setState({
    //   count: 10
    // })

    // +1
    this.setState({
      // 基于当前状态值来更新状态:
      count: this.state.count + 1
    })
  }

  render() {
    console.log('render')
    return (
      <div>
        <h1>计数器:{this.state.count}</h1>
        <button onClick={this.handleClick}>+1</button>
      </div>
    )
  }
}

二丶组件通讯

1.父子组件通讯

父级到子级:函数式组件通过参数来接收,class类组件通过this.props来接收 

props进阶用法:

1.props有一个children属性,props.children=当前标签页中间的值,children中间可写入表达式

2.props校验,需要安装引入  import PropTypes from "prop-types"  校验包,使用方法:组件名.PropTypes={ 值:PropTypes.类型 },如:List.PropTypes={ name:PropTypes.Array },

常见的类型有:array,bool,func,number,object,string,

React元素类型:element ,

必填项:isRequired

特定结构的对象:shape({ })

默认值:defaultProps

import { Component } from 'react'

// 函数组件
// 组件接收数据:通过 参数props 来接收
//  props 是一个对象
const Hello = props => {
  console.log('接收到传递给组件的数据:', props)
  return <div>Hello 组件</div>
}

class Hello1 extends Component {
  render() {
    console.log('接收属性:', this.props)
    return <div>Hello1 组件</div>
  }
}

export default class App extends Component {
  render() {
    return (
      <div>
        {/* 给组件传递属性 */}
        <Hello name="jack" age="19"></Hello>

        {/* 给 类组件 传递属性 */}
        <Hello1 name="jack" age="19"></Hello1>

        {/* <div id=""></div> */}
      </div>
    )
  }
}

子级到父级:通过触发绑定在子级标签上的事件来传递参数

import { Component } from "react";

// 创建父组件
class Parent extends Component {
  state = {
    money: 10000,
    car: "二手-奥拓",
  };

  // 1 父组件提供一个回调函数
  buyPhone = (price) => {
    // console.log('父组件接收到子组件传递过来的数据:', price)
    this.setState({
      money: this.state.money - price,
    });
  };

  render() {
    return (
      <div>
        <h1>我是父组件:</h1>
        <Child
          money1={this.state.money}
          car1={this.state.car}
          // 2 将回调函数传递给 子组件
          buyPhone1={this.buyPhone}
        />
      </div>
    );
  }
}

// // 创建子组件
// const Child = props => {
//   // console.log('子组件:', props)
//   return (
//     <div>
//       我是子组件 - {props.money1} - {props.car1}
//       <div>
//         {/* 3 子组件调用父组件传递过来的 回调,并且将要传递的数据,作为参数传递 */}
//         <button onClick={() => props.buyPhone1(100)}>买手机</button>
//       </div>
//     </div>
//   )
// }

class Child extends Component {
  render() {
    const { money1, car1, buyPhone1 } = this.props;
    console.log("子组件", money1);

    return (
      <div>
        我是子组件 - {money1} - {car1}
        <div>
          <button onClick={() => buyPhone1(200)}>买手机</button>
        </div>
      </div>
    );
  }
}

export default class App extends Component {
  render() {
    return (
      <div>
        <Parent />
      </div>
    );
  }
}

2.兄弟组件通讯

创建一个中转父组件,通过子传父向父级传递参数, 父级拿到数据后,通过父传子传递,实现兄弟组件通讯

3.跨组件通讯(Context)

通过react的creactContext 来进行跨组件通讯,实现思路:先将creactContext进行结构,解构Provider(提供数据),Consumer(消化数据)两个属性,Provider提供value属性,来进行传值,Consumer中获取value数据,需要在标签包裹中创建一个表达式,写入一个回调函数,其中回调函数的参数就是当前value值

import React, { Component, createContext } from "react";
import "./App.css";

// Context 跨组件传递数据:

// 目标:将 App 组件中的状态数据,传递给 Child 组件

const { Provider, Consumer } = createContext();

const Node = () => (
  <div className="node">
    Node
    <SubNode />
  </div>
);
const SubNode = () => (
  <div className="sub-node">
    SubNode
    <Consumer>
      {(color) => (
        <ul style={{ color }}>
          <li>{color}</li>
        </ul>
      )}
    </Consumer>
    <Child />
  </div>
);

// 需要接收 App 组件中共享的数据
const Child = () => (
  <div className="child">
    Child
    <Consumer>
      {(color) => <p style={{ color }}>接收到数据:{color}</p>}
    </Consumer>
  </div>
);

export default class App extends Component {
  state = {
    color: "blue",
  };

  render() {
    return (
      <Provider value={this.state.color}>
        <div className="app">
          <h1>我是App组件</h1>
          <Node />
        </div>
      </Provider>
    );
  }
}

三丶生命周期

React生命周期分为三个阶段:挂载(实例化期)、更新(存在期)、卸载(销毁期)。
1.挂载期:一个组件实例初次北创建的过程。
2.更新期:组件在创建后再次渲染的过程。
3.卸载期:组件在使用完后被销毁的过程。

挂载阶段

触发的钩子函数:

1.constructor: 在创建组件时触发,可以初始化state中的数据, 为事件绑定this

2.render:  每次组件渲染(初次渲染组件和更新组件)都会被触发;作用是渲染UI; 不能够调用 setState 因为setState会更新数据,这样会导致递归渲染数据

3.componentDidMount::DOM已经渲染完成;可以进行DOM操作和网络请求 

更新阶段

触发的钩子函数:componentDidUpdate

此钩子函数为更新阶段触发的钩子函数,有一个参数prevProps,是上一个props的值,一般用来判断是否需要更新数据,调用时会先触发render渲染函数,之后在触发更新的钩子函数。

如果要调用:setState()更新状态或网络请求,必须包放一个if语句;否则会导致递归更新; 因为调用 setState会触发render函数;render触发后,就会触发componentDidUpdate; 这样就导致了-递归更新,

更新组件的几种情况:

1.组件接收到一个新的属性,会触发render函数

2.调用this.setState更新数据时,会触发render函数

3.调用forceupdata(),强制刷新页面时,会触发render函数

卸载阶段

触发的钩子函数:componentWillUnmount 

组件将要卸载的时候会被触发,可以做清除定时器

四丶setState进阶用法

1.setState延迟更新(批量更新):

执行过程:react 框架内部有一个表示批量更新的标记 isBatchingUpdates,当我们点击按钮触发了 react 自己的事件后,这个标记就被修改为 true,表示批量更新,所以,此时调用 setState 的时候,并不会立即更新状态,而是存储到了一个队列中,将来等到所有的操作都执行完成后,React 就会合并所有的状态更新,一次性的更新状态,最终,将 isBatchingUpdates 标记设置为 false

import { Component } from 'react'

class Counter extends Component {
  state = {
    count: 0
  }

  handleClick = () => {
    this.setState({
      count: this.state.count + 1
    })
    this.setState({
      count: this.state.count + 2
    })
    this.setState({
      count: this.state.count + 3
    })

    console.log('count:', this.state.count) // 结果为3
  }

  render() {
    console.log('render')
    return (
      <div>
        <h1>计数器:{this.state.count}</h1>
        <button onClick={this.handleClick}>打豆豆</button>
      </div>
    )
  }
}

export default class App extends Component {
  render() {
    return (
      <div>
        <Counter />
      </div>
    )
  }
}

2.改变state立即生效(每次执行拿到prevState最新的值,依次执行,返回数据渲染)

  this.setState(prevState => {
      return {
        count: prevState.count + 1
      }
    })
    this.setState(prevState => {
      return {
        count: prevState.count + 2
      }
    })
    this.setState(prevState => {
      return {
        count: prevState.count + 3
      }
    })


   console.log('count:', this.state.count)  // 结果为6

3.setState同步与异步

同步的情况也就是setState延迟更新(批量更新)的方式

异步方式:每次调用 setState 都会立即更新状态,并且让组件重新渲染,因为 定时器 中的代码是异步代码,定时器中的代码不会被立即执行而是放到了事件队列中,事件队列中的代码,会在 JS 主线程(同步代码)都执行完成后,再执行。当主线程中的代码执行完成后,React 已经将 isBatchingUpdates 标记设置为 false,此时,再调用 setState(),此时,因为批量合并更新的标记已经是 false,所以,React 会调用一次 setState 就立即更新一次状态,并且立即渲染

     setTimeout(() => {
       this.setState({
         count: this.state.count + 1
       })
       this.setState({
         count: this.state.count + 2
       })
     }, 0)

解决setTimeout中不断渲染的问题:

通过一个 unstable_batchedUpdates API 可以让 setState,在定时器中执行,也跟正常情况表现一致了,也就是:批量合并更新

   setTimeout(() => {
      ReactDOM.unstable_batchedUpdates(() => {
        this.setState({
          count: this.state.count + 1
        })
        this.setState({
          count: this.state.count + 2
        })
      })
    }, 0)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值