中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

React?Context與setState如何使用

發布時間:2022-11-29 09:57:35 來源:億速云 閱讀:131 作者:iii 欄目:開發技術

這篇文章主要介紹“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>
            {/* 1.使用children實現插槽 */}
            <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>
            {/* 2.使用props實現插槽 */}
            <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.創建一個Context
    const ThemeContext = React.createContext({ color: "blue", size: 10 })
    export default ThemeContext

    user-context.js

    import React from "react"
    // 1.創建一個Context
    const 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>
            {/* 1.給Home傳遞數據 */}
            {/* <Home name="why" age={18}/>
            <Home name={info.name} age={info.age}/>
            <Home {...info}/> */}
            {/* 2.普通的Home */}
            {/* 第二步操作: 通過ThemeContext中Provider中value屬性為后代提供數據 */}
            <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為某一個Context
    HomeInfo.contextType = ThemeContext
    export default HomeInfo

    Context.Consumer

    這里,React 組件也可以訂閱到 context 變更。這能讓你在 函數式組件 中完成訂閱 context。

    這里需要 函數作為子元素(function as child)這種做法;

    這個函數接收當前的 context 值,返回一個 React 節點;

    什么時候使用Context.Consumer呢?

    1.當使用value的組件是一個函數式組件時;

    2.當組件中需要使用多個Context時;

    import ThemeContext from "./context/theme-context"
    function HomeBanner() {
      return <div>
        {/* 函數式組件中使用Context共享的數據 */}
        <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如何使用”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    新郑市| 孟连| 枣强县| 深圳市| 莱阳市| 尚义县| 丰都县| 横峰县| 青浦区| 中方县| 教育| 五指山市| 象州县| 博客| 绥芬河市| 盱眙县| 兴山县| 沐川县| 南宫市| 五台县| 专栏| 哈尔滨市| 沈阳市| 磐石市| 承德市| 寻甸| 壤塘县| 平乐县| 陆丰市| 依兰县| 东城区| 岑溪市| 泰来县| 东方市| 宁城县| 习水县| 靖江市| 南充市| 彭水| 利津县| 平舆县|