文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

React Context与setState如何使用

2023-07-04 16:34

关注

这篇文章主要介绍“React Context与setState如何使用”,在日常操作中,相信很多人在React Context与setState如何使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”React Context与setState如何使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

React中的插槽(slot)

React对于需要插槽的情况非常灵活,有两种方案可以实现:

组件的children子元素;

props属性传递React元素

children实现插槽

每个组件都可以获取到 props.children:它包含组件的开始标签和结束标签之间的内容。

App.jsx

import React, { Component } from 'react'import NavBar from './nav-bar'import NavBarTwo from './nav-bar-two'export class App extends Component {  render() {    const btn = <button>按钮2</button>    return (      <div>        {}        <NavBar>          <button>按钮</button>          <h3>哈哈哈</h3>          <i>斜体文本</i>        </NavBar>      </div>    )  }}export default App

NavBar.jsx

import React, { Component } from 'react'// import PropTypes from "prop-types"import "./style.css"export class NavBar extends Component {  render() {    const { children } = this.props    console.log(children)    return (      <div className='nav-bar'>        <div className="left">{children[0]}</div>        <div className="center">{children[1]}</div>        <div className="right">{children[2]}</div>      </div>    )  }}// NavBar.propTypes = {//   children: PropTypes.array// }export default NavBar

props实现插槽

app.jsx

import React, { Component } from 'react'import NavBar from './nav-bar'import NavBarTwo from './nav-bar-two'export class App extends Component {  render() {    const btn = <button>按钮2</button>    return (      <div>        {}        <NavBarTwo           leftSlot={btn}          centerSlot={<h3>呵呵呵</h3>}          rightSlot={<i>斜体2</i>}        />      </div>    )  }}export default App

NavBarTwo.jsx

import React, { Component } from 'react'export class NavBarTwo extends Component {  render() {    const { leftSlot, centerSlot, rightSlot } = this.props    return (      <div className='nav-bar'>        <div className="left">{leftSlot}</div>        <div className="center">{centerSlot}</div>        <div className="right">{rightSlot}</div>      </div>    )  }}export default NavBarTwo

Context应用场景

非父子组件数据的共享:

在开发中,比较常见的数据传递方式是通过props属性自上而下(由父到子)进行传递。

但是对于有一些场景:比如一些数据需要在多个组件中进行共享(地区偏好、UI主题、用户登录状态、用户信息等)。

如果我们在顶层的App中定义这些信息,之后一层层传递下去,那么对于一些中间层不需要数据的组件来说,是一种冗余的操作。

但是,如果层级更多的话,一层层传递是非常麻烦,并且代码是非常冗余的:

React提供了一个API:Context;

Context 提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递 props;

Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言;

Context相关API

React.createContext

创建一个需要共享的Context对象:

如果一个组件订阅了Context,那么这个组件会从离自身最近的那个匹配的 Provider 中读取到当前的context值;

defaultValue是组件在顶层查找过程中没有找到对应的Provider,那么就使用默认值

theme-context.js

import React from "react"// 1.创建一个Contextconst ThemeContext = React.createContext({ color: "blue", size: 10 })export default ThemeContext

user-context.js

import React from "react"// 1.创建一个Contextconst UserContext = React.createContext()export default UserContext

Context.Provider

每个 Context 对象都会返回一个 Provider React 组件,它允许消费组件订阅 context 的变化:

Provider 接收一个 value 属性,传递给消费组件;

一个 Provider 可以和多个消费组件有对应关系;

多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据;

当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染;

import React, { Component } from 'react'import Home from './Home'import ThemeContext from "./context/theme-context"import UserContext from './context/user-context'import Profile from './Profile'export class App extends Component {  constructor() {    super()    this.state = {      info: { name: "kobe", age: 30 }    }  }  render() {    const { info } = this.state    return (      <div>        <h3>App</h3>        {}        {}        {}        {}        <UserContext.Provider value={{nickname: "kobe", age: 30}}>          <ThemeContext.Provider value={{color: "red", size: "30"}}>            <Home {...info}/>          </ThemeContext.Provider>        </UserContext.Provider>        <Profile/>      </div>    )  }}export default App

Class.contextType

挂载在 class 上的 contextType 属性会被重赋值为一个由 React.createContext() 创建的 Context 对象:

这能让你使用 this.context 来消费最近 Context 上的那个值;

你可以在任何生命周期中访问到它,包括 render 函数中;

import React, { Component } from 'react'import ThemeContext from './context/theme-context'import UserContext from './context/user-context'export class HomeInfo extends Component {  render() {    // 4.第四步操作: 获取数据, 并且使用数据    console.log(this.context)    return (      <div>        <h3>HomeInfo: {this.context.color}</h3>        <UserContext.Consumer>          {            value => {              return <h3>Info User: {value.nickname}</h3>            }          }        </UserContext.Consumer>      </div>    )  }}// 3.第三步操作: 设置组件的contextType为某一个ContextHomeInfo.contextType = ThemeContextexport default HomeInfo

Context.Consumer

这里,React 组件也可以订阅到 context 变更。这能让你在 函数式组件 中完成订阅 context。

这里需要 函数作为子元素(function as child)这种做法;

这个函数接收当前的 context 值,返回一个 React 节点;

什么时候使用Context.Consumer呢?

当使用value的组件是一个函数式组件时;

当组件中需要使用多个Context时;

import ThemeContext from "./context/theme-context"function HomeBanner() {  return <div>    {}    <ThemeContext.Consumer>      {        value => {          return <h3> Banner theme:{value.color}</h3>        }      }    </ThemeContext.Consumer>  </div>}export default HomeBanner

我们什么使用setState

开发中我们并不能直接通过修改state的值来让界面发生更新:

因为我们修改了state之后,希望React根据最新的State来重新渲染界面,但是这种方式的修改React并不知道数据发生了变化;

React并没有实现类似于Vue2中的Object.defineProperty或者Vue3中的Proxy的方式来监听数据的变化;

我们必须通过setState来告知React数据已经发生了变化;

疑惑:在组件中并没有实现setState的方法,为什么可以调用呢?

原因很简单,setState方法是从Component中继承过来的。

setState异步更新

setState的更新是异步的?

最终打印结果是Hello World;

可见setState是异步的操作,我们并不能在执行完setState之后立马拿到最新的state的结果

setState设计为异步,可以显著的提升性能;

如果每次调用 setState都进行一次更新,那么意味着render函数会被频繁调用,界面重新渲染,这样效率是很低的;

最好的办法应该是获取到多个更新,之后进行批量更新;

如果同步更新了state,但是还没有执行render函数,那么state和props不能保持同步;

state和props不能保持一致性,会在开发中产生很多的问题;

如何获取异步的结果

式一:setState的回调

setState接受两个参数:第二个参数是一个回调函数,这个回调函数会在更新后会执行;

格式如下:setState(partialState, callback)

changeText() {this.setState({message: '你好'}), () => {console.log(this.state.message)}}

当然我们也可以在生命周期函数

componentDidUpdate(precProps, provState, snapshot) {console.log(this.state.message)}

setState一定是异步的吗(React18之前)

其实分成两种情况:

在组件生命周期或React合成事件中,setState是异步;

在setTimeout或者原生dom事件中,setState是同步;

setState默认是异步的 (React18之后)

在React18之后,默认所有的操作都被放到了批处理中(异步处理)。

如果希望代码可以同步会拿到,则需要执行特殊的flushSync操作

import React, { Component } from 'react'import { flushSync } from 'react-dom'function Hello(props) {  return <h3>{props.message}</h3>}export class App extends Component {  constructor(props) {    super(props)    this.state = {      message: "Hello World",      counter: 0    }  }  componentDidMount() {    // 1.网络请求一: banners    // 2.网络请求二: recommends    // 3.网络请求三: productlist  }  changeText() {    setTimeout(() => {      // 在react18之前, setTimeout中setState操作, 是同步操作      // 在react18之后, setTimeout中setState异步操作(批处理)      flushSync(() => {        this.setState({ message: "你好啊, 李银河" })      })      console.log(this.state.message)    }, 0);  }  increment() {  }  render() {    const { message, counter } = this.state    console.log("render被执行")    return (      <div>        <h3>message: {message}</h3>        <button onClick={e => this.changeText()}>修改文本</button>        <h3>当前计数: {counter}</h3>        <button onClick={e => this.increment()}>counter+1</button>        <Hello message={message}/>      </div>    )  }}export default App

到此,关于“React Context与setState如何使用”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯