當咱們應用比較龐大的時候, 又或者說當你當前組件的文件比較大,咱們能夠將組件進行賴加載, 在某些狀況下, 它纔會被加載使用, 這個時候 咱們可使用 React.lazy
配合 Suspense
使用react
import React, { Suspense } from 'react';
const LazyPage = React.lazy(() => import('../lazy/Lazy'));
function MyLazyPage() {
return (
<div> <Suspense fallback={<div>Loading...</div>}> <LazyPage /> </Suspense> </div>
);
}
export default MyLazyPage
複製代碼
以上代碼, lazyPage組件 將會 懶加載, 在加載過程當中, 將會顯示 Suspense
定義的fallback 組件數組
配合Route使用react-router
import React, { Suspense, lazy } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));
const App = () => (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
</Switch>
</Suspense>
</Router>
);
複製代碼
React.lazy 目前只支持==默認導出==(default exports), 若是你想經過==命名導出的方式==dom
能夠參考官方這個例子 ide
默認導出, 就是你導出的時候, 導出的數據你能夠本身想怎麼命名均可以, 可是命名導出, 你導出的名稱必須一致函數
當你某個屬性會在多個組件中使用到的時候, 咱們能夠考慮使用Context, 它能夠避免你一層層地往下傳遞值, 它有點相似於Vue當中 Provider和 injectui
要想實現這個功能,咱們首先得建立一個context對象 你能夠經過 React.createContext(初始的值)
來 建立一個 context 對象, 它還會返回 Provider
和 Consumer
對象, 它們都是組件, 你可使用它,this
const nameContext = React.createContext('evanyou') // 建立一個context, 默認值爲evanyou
複製代碼
Provider 接受一個value 值, value 值能夠更新初始值的, 當value 值發生變化時, 它底下的全部組件都會從新渲染, Provider 及其內部 consumer 組件都不受制於 shouldComponentUpdate 函數spa
<nameContext.Provider value="yaojin">
<Second /> <OtherPage /> </nameContext.Provider> 複製代碼
將默認的evanyou 值更新成yaojin, 須要注意的是, 儘可能不要將值寫在value中, 若是value 是一個對象 那麼都會不斷返回一個新的對象, 其底下的組件都會從新渲染, 此時能夠考慮將該值放到父組件的state 中3d
如何讀取呢 ? 經過 contextType 屬性 能夠獲取到離最近的那個匹配的 Provider 中讀取context的值 Provider
從新渲染,
class Second extends React.Component {
static contextType = nameContext
render() {
return <div> {this.context} <Transmit value={this.context}/> </div> } } 複製代碼
==contextType 屬性== 僅用在 class 組件中
那在函數組件應該如何讀取我須要的值呢 ? 咱們還可使用 Consumer
, 在其內部, 你須要使用一個函數來接受context的值, 這個函數應該作爲子元素
function OtherPage() {
return <nameContext.Consumer> {value => <div >{value} </div> } </nameContext.Consumer> } 複製代碼
有時候,咱們想操做真實的DOM元素,例如得到某個input的焦點, 或者說或許某個組件的實例, ref 能夠幫咱們實現這一點
經過 React.createRef()
建立一個ref
在元素或者組件中經過 ref屬性
來綁定對應的ref
==ref 只能用於 在 class 組件中使用, 不能再函數組件中使用==
class GetDom extends React.Component {
constructor(props) {
super(props)
// 建立一個ref
this.inputRef = React.createRef()
this.focusTextInput = this.foucusInput.bind(this)
}
foucusInput() {
console.log('父組件經過ref拿到該組件實例, 直接調用這個方法了')
// 經過current能夠訪問到ref綁定的dom元素或者class組件
this.inputRef.current.focus()
}
render() {
return (
<div>
{/* ref獲取inputDom元素 */}
<input ref={this.inputRef} />
</div>
)
}
}
export default class GetClass extends React.Component {
constructor (props) {
super(props)
this.classRef = React.createRef()
}
componentDidMount() {
this.classRef.current.foucusInput()
}
render () {
return (
<div>
{/* ref獲取GetDom組件實例 */}
<GetDom ref={this.classRef} />
</div>
)
}
}
複製代碼
不一樣於經過React.createRef()
你還能夠經過 ==回調 Refs== 來存儲 ref, 在須要使用的時候, 調用它
export default class GetClass extends React.Component {
constructor (props) {
super(props)
this.refInfo = null
this.cacheRef = refData => {
this.refInfo = refData;
}
this.triggerChildrenFun = () => {
if (this.cacheRef) {
this.refInfo.foucusInput ()
}
}
}
componentDidMount() {
this.triggerChildrenFun()
}
render () {
return (
<div> {/* ref獲取GetDom組件實例 */} <GetDom ref={this.cacheRef} /> </div> ) } } 複製代碼
render 須要 建立多個元素的時候,都須要使用 div 來包裹, 若是不想使用這個div來包裹元素, 可使用 Fragments
, 它相似於一個<>
的標籤包裹你的元素, 它不支持key 或者 傳遞屬性
若是你想使用key 屬性 , 你能夠顯示得使用 <React.Fragment>
包裹元素
Hoc在React中稱爲高階組件, 高階組件的做用在於一些公用邏輯放到高階組件中, 它本質上其實就是一個函數組件,可是它接受另外的組件做爲參數, 並返回該組件
經過高階組件, 咱們能夠把公用的方法以及state都提取都高階組件中, 在經過props的方式傳遞到對應的組件中,
function HocWrap(title) {
return WrapComponent => {
return class extends React.Component {
// 修改在 React-devtool 中高階組件名稱
static displayName = `HocWrap(${WrapComponent})`
constructor(prosp) {
super(prosp)
this.state = {
username: '',
password: '',
rePassword: '',
}
this.onChange = this.onChange.bind(this)
this.composeChange = this.composeChange.bind(this)
}
onChange(stateName, stateValue) {
this.setState({
[stateName]: stateValue,
})
}
handleSubmit = e => {
e.preventDefault()
const { username, password, rePassword } = this.state
if (rePassword) {
alert(
`用戶名: ${username}, 密碼: ${password}, 確認密碼: ${rePassword}`,
)
} else {
alert(`用戶名: ${username}, 密碼: ${password}`)
}
}
composeChange(name) {
return e => this.onChange(name, e.target.value)
}
render() {
// 抽離出公用的方法
const mapFunToProps = {
composeChange: this.composeChange,
handleSubmit: this.handleSubmit,
}
return (
<div> <h1>{title}</h1> <WrapComponent {...this.state} {...mapFunToProps} /> </div> ) } } } } 複製代碼
在高階組件中, 若是你想拿到 被包裝 組件的實例, 你可使用ref轉發 來實現, React 提供了一個 React.forwardRef
方法來建立一個組件, 這個方法, 不但能夠接受props, 還能夠接受ref做爲參數, 而後咱們就能夠 經過 React.createRef
來建立 ref , 將這個ref 傳遞到 React.forwardRef
方法中
// Hoc組件內部是一個函數組件 最終返回一個React.forwardRef建立的組件, 它裏面返回的是高階組件中被包裹的組件, 並將ref做爲props進行傳遞
return React.forwardRef((props, ref) => {
return <HocRef forwardedRef={ref} /> }) 複製代碼
由於高階組件是函數組件, 咱們須要經過一個層class 包裹, 由於ref 只有 class 組件可使用, 只有它能夠建立一個ref, 建立完以後咱們才能夠經過 React.forwardRef
讓函數組件接受到這個ref, 有了這個ref ,咱們就能夠經過props的形式傳遞到內部的包裹組件了, 能夠看上面的代碼, 咱們將ref, 經過props 傳遞給包裹組件了, 那麼內部包裹組件就能夠在經過props讀取到ref, 經過ref屬性 進行綁定關聯了
==只須要明確 ref 只有在class組件中建立而且使用, ref不能像props同樣傳遞給子組件, 因此當遇到函數組件的時候, 咱們想拿到這個ref,就能夠經過React.forwardRef來接收ref, 又或者說你想將這個ref往下傳遞==
// 向外暴露的是高階組件的返回值~包裝了 Register 組件返回了一個新組件
const Hoc = HocWrap('註冊')(Register)
export default class Wrap extends React.Component {
render() {
const ref = React.createRef()
return (
<div> <Hoc ref={ref}></Hoc> </div>
)
}
}
複製代碼
ReactDOM.createPortal 可讓元素插入到別的dom節點上, 不是單單地插入到父節點上
ReactDOM.createPortal(child, container)
複製代碼
第一個參數(child)是任何可渲染的 React 子元素,例如一個元素,字符串或 fragment。第二個參數(container)是一個 DOM 元素