目錄
- 父子組件傳值- props
- 父傳子
- 子傳父
- 嵌套組件傳值-Context API
- 概念
- React.createContext API
- Provider組件
- 正確示例
- 錯誤示例
- 消費 Context
- React.Consumer組件
- useContext Hook
- 區別
- 使用場景
- 舉例說明-用戶信息
- 狀態管理-Redux
父子組件傳值- props
在React中父子組件傳值是單向數據流
=> 數據必須是由父級傳到子級或者子級傳遞給父級層層傳遞!
父傳子
父組件通過在子組件的JSX標簽上添加屬性的方式來傳遞數據,子組件通過 props 對象接收。
傳遞的數據類型是不受限制的 = > 可以是字符串、數字、數組、對象、函數、甚至JSX元素。
-
父組件
<son 子組件接收的屬姓名=父組件的屬性值></son>
import {useState} from 'react' import Funcom from '../component/Funcom' import Clcom from '../component/Clcom'export default function Page1(){const [num, setNum] = useState(1)return (<div>{/* 函數子組件 */}<Funcom num={num}/>{/* 類子組件 */}<Clcom num ={num}/><button onClick={()=>{setNum(preNum=>preNum+1)}}>editNum</button></div>) }
-
子組件:
- 函數子組件組件:在調用函數時將props作為參數傳入;
function FunSon(props){ // props直接使用 }
export default function Fun(props){console.log('渲染了') // 無論有沒有接收參數只要父組件更新都會重新渲染子組件return (<div><h4>函數子組件==》{props.num}</h4></div>) }
- 類子組件:通過this獲取props
class ClaSon extends React.Component{// this.props使用 }
import React from 'react'export default class Clcom extends React.Component {render() {console.log('render') // 無論有沒有接收參數只要父組件更新都會重新渲染子組件return (<><h4>類組件==》{this.props.num}</h4></>)} }
- 函數子組件組件:在調用函數時將props作為參數傳入;
子傳父
子組件不能直接修改父組件的狀態(數據單向流動)
,果需要,父組件必須傳遞一個函數給子組件作為 prop,子組件在需要時調用這個函數,將數據作為參數傳回給父組件。
- 父組件
<Son 子組件調用的方法名={父組件的方法}></Son>
- 子組件
// 當子組件想要修改父組件的數據時 // val是要修改的值props.方法名(val) // 函數組件this. props.方法名(val) // 類組件
- 舉例說明
父組件
函數子組件import {useState} from 'react' import Funcom from '../component/Funcom' import Clcom from '../component/Clcom'export default function Page1(){const [num, setNum] = useState(1)function editNum(val){setNum(val)}return (<div>{/* 函數子組件 */}<Funcom num={num} editNum={editNum}/>{/* 類子組件 */}<Clcom num ={num} editNum={editNum}/></div>) }
類子組件export default function Fun(props){return (<div><h4>函數子組件==》{props.num}</h4><button onClick={()=>{props.editNum(props.num+2)}}>函數組件editNum</button></div>) }
import React from 'react'export default class Clcom extends React.Component {render() {console.log('render')return (<><h4>類組件==》{this.props.num}</h4><button onClick={()=>{this.props.editNum(this.props.num+1)}}>類組件editNum</button></>)} }
嵌套組件傳值-Context API
概念
Context API 是 React 提供的一種組件間通信機制,允許數據在組件樹中直接傳遞,無需通過 props 逐層傳遞。
React.createContext API
React.createContext 是一個函數,用于創建一個Context對象 => 該對象是管理 “全局”或“跨組件”數據的容器和通信機制。
React.createContext(defaultValue)
-
參數:defaultValue;
當一個組件在樹中找不到匹配的 Provider 時,React.Consumer/useContext就會返回這個 defaultValue;
這個默認值對于測試組件或在沒有提供 Provider 的情況下非常有用
-
返回值:一個Context對象
{$$typeof: Symbol(react.context), // React 內部用于識別類型的符號_currentValue: 'light', // 內部保存的當前值Provider: { ... }, // Provider 組件Consumer: { ... }, // Consumer 組件 (已較少使用)displayName: undefined, // 用于 React DevTools 顯示的名稱 }
Provider組件
Provider組件是React.createContext函數返回對象的屬性,允許消費組件訂閱 Context 的變化。
<MyContext.Provider value={...}><!-- 子組件樹-->
</MyContext.Provider>
value就是要傳遞給所有下層組件的數據,只要 value發生變化,所有訂閱該 Context 的后代組件都會強制重新渲染
,即使它們使用了 React.memo 或 shouldComponentUpdate。
正確示例
const ThemContext = createContext({theme:'right', color: 'red'})const [theme, setTheme] = useState({theme:'right', color: 'red'})return (<div><ThemContext.Provider value={theme}>{/* 其中所有的子組件以及其子組件都可以獲取到value */}<Funcom /><Clcom /></ThemContext.Provider></div>)
錯誤示例
<div><ThemContext.Provider value={{theme:'right', color: 'red'}}>{/* 其中所有的子組件以及其子組件都可以獲取到value */}<Funcom /><Clcom /></ThemContext.Provider>
</div>
每次渲染時,value={ theme:‘right’, color: ‘red’ }都會創建一個全新的對象,導致所有消費者不必要的重渲染。
消費 Context
kan su me
React.Consumer組件
React.Consumer是類組件中訂閱 Context 變更的方式,函數組件已經逐漸使用useContext這個hook來替代了。
其子元素是一個函數,函數的參數就是 ThemeContext 的當前值,返回值就是需要渲染的vodm;
<ThemeContext.Consumer>{value=>{vdom}}</ThemeContext.Consumer>
舉例說明
-
將context提取為一個單獨的文件themeContext
import {createContext} from 'react' export default createContext({theme:'right', color: 'red'})
-
在頂級組件引入
import {useState} from 'react' import Funcom from '../component/Funcom' import Clcom from '../component/Clcom' import ThemContext from '../utils/themeContext' export default function Page1(){const [theme, setTheme] = useState({theme:'right', color: 'red'})function editTheme(){setTheme(prevalue => ({...prevalue, theme: prevalue.theme=='right' ? 'dack' : 'right',}))}return (<div><ThemContext.Provider value={theme}>{/* 其中所有的子組件以及其子組件都可以獲取到value */}<Funcom /><Clcom /><button onClick={editTheme}>edittheme</button></ThemContext.Provider></div>) }
-
子組件中若是不需要使用則完全不需要改變
-
在想要使用的組件去消費,比如此處在孫組件使用
import React from 'react'import ThemeContext from '../utils/themeContext'class SonFun2 extends React.Component{render(){console.log('孫組件')return(<ThemeContext.Consumer>{value=>(<><h4>今天的主題是:{value.theme}</h4><div>今天的顏色是:{value.color}</div></>)}</ThemeContext.Consumer>)}}
當在頂級組件點擊按鈕修改value值時會重新渲染所有組件,包括子組件(因為通過setState去修改數據本身就會渲染所有子組件)
useContext Hook
useContext是函數組件中訂閱 Context 變更的方式
const value = useContext(ThemeContext)
value就是要傳遞給所有下層組件的數據,只要 value發生變化,所有訂閱該 Context 的后代組件都會強制重新渲染
。
舉例說明
function SonFun(){const value = useContext(ThemeContext)return (<div><h4>function</h4><h4>今天的主題是:{value.theme}</h4><div>今天的顏色是:{value.color}</div></div>)
}
區別
函數組件 | 類組件 | |
---|---|---|
方式 | useContext API | Context.consumer組件 |
語法 | 只需要在函數頂部調用hook ,簡單明了 | 需要在組件jsx語法中嵌套一個函數,語法稍顯冗長 |
易讀性 | 可以并行調用多個context,簡單易懂 | 若是存在多個context,容易造成回調地獄 |
性能 | 基本相同 | 基本相同 |
使用場景
推薦在值不經常改變
的地方使用context,如主題切換、用戶信息認證、管理一些全局的、許多組件都需要的數據;
對于頻繁更新的數據, 如表單輸入、實時坐標等,Context 可能不是最優解,因為只要 Context 的 value 變化,所有消費該 Context 的組件都會重新渲染,即使它們只使用了 value 的一部分。
舉例說明-用戶信息
狀態管理-Redux
redux