<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
React對於需要插槽的情況非常靈活,有兩種方案可以實現:
元件的children子元素;
props屬性傳遞React元素
每個元件都可以獲取到 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> <h2>哈哈哈</h2> <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
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={<h2>呵呵呵</h2>} 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
非父子元件資料的共用:
在開發中,比較常見的資料傳遞方式是通過props屬性自上而下(由父到子)進行傳遞。
但是對於有一些場景:比如一些資料需要在多個元件中進行共用(地區偏好、UI主題、使用者登入狀態、使用者資訊等)。
如果我們在頂層的App中定義這些資訊,之後一層層傳遞下去,那麼對於一些中間層不需要資料的元件來說,是一種冗餘的操作。
但是,如果層級更多的話,一層層傳遞是非常麻煩,並且程式碼是非常冗餘的:
React提供了一個API:Context;
Context 提供了一種在元件之間共用此類值的方式,而不必顯式地通過元件樹的逐層傳遞 props;
Context 設計目的是為了共用那些對於一個元件樹而言是“全域性”的資料,例如當前認證的使用者、主題或首選語言;
建立一個需要共用的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 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> <h2>App</h2> {/* 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 屬性會被重賦值為一個由 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> <h2>HomeInfo: {this.context.color}</h2> <UserContext.Consumer> { value => { return <h2>Info User: {value.nickname}</h2> } } </UserContext.Consumer> </div> ) } } // 3.第三步操作: 設定元件的contextType為某一個Context HomeInfo.contextType = ThemeContext export default HomeInfo
這裡,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 <h2> Banner theme:{value.color}</h2> } } </ThemeContext.Consumer> </div> } export default HomeBanner
開發中我們並不能直接通過修改state的值來讓介面發生更新:
因為我們修改了state之後,希望React根據最新的State來重新渲染介面,但是這種方式的修改React並不知道資料發生了變化;
React並沒有實現類似於Vue2中的Object.defineProperty或者Vue3中的Proxy的方式來監聽資料的變化;
我們必須通過setState來告知React資料已經發生了變化;
疑惑:在元件中並沒有實現setState的方法,為什麼可以呼叫呢?
原因很簡單,setState方法是從Component中繼承過來的。
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) }
其實分成兩種情況:
在元件生命週期或React合成事件中,setState是非同步;
在setTimeout或者原生dom事件中,setState是同步;
在React18之後,預設所有的操作都被放到了批次處理中(非同步處理)。
如果希望程式碼可以同步會拿到,則需要執行特殊的flushSync操作
import React, { Component } from 'react' import { flushSync } from 'react-dom' function Hello(props) { return <h2>{props.message}</h2> } 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> <h2>message: {message}</h2> <button onClick={e => this.changeText()}>修改文字</button> <h2>當前計數: {counter}</h2> <button onClick={e => this.increment()}>counter+1</button> <Hello message={message}/> </div> ) } } export default App
到此這篇關於React Context與setState詳解使用方法的文章就介紹到這了,更多相關React Context與setState內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45