当咱们应用比较庞大的时候, 又或者说当你当前组件的文件比较大,咱们能够将组件进行赖加载, 在某些状况下, 它才会被加载使用, 这个时候 咱们可使用 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 元素