前言: 本类文章初衷只用作记录个人的学习博客,哪里有漏补哪里,不做任何其他商业用途。欢迎讨论,不喜勿喷。后面要是有遗漏的相关知识点,也会相应的补上。如果本篇文章能帮到你,我也会很愉快,共勉😁
目录
- Ref
- useContext
- HOC
Ref
ref的特点:
- 更改ref的值时不会触发重新渲染
- 每次页面、组件重新渲染时ref的值是不会改变的
- 可以在除渲染过程以外的场景下修改和更新ref的值
- 在渲染期间(未初始化完成)无法访问、修改ref的值
class与hooks的不同写法
class
写法
js
import React, { Component, createRef } from 'react'
export default class ClassBasic extends Component {
constructor(props) {
super(props);
this.inpRef = createRef();
}
handleClick = () => {
// 点击按钮 文本框获取焦点
this.inpRef.current.focus();
}
render() {
return (
<div>
<input ref={this.inpRef} />
<button onClick={this.handleClick}>Click me</button>
</div>
)
}
}
hook
写法
js
import React, { useRef } from 'react'
export default function HooksBasic() {
const inpRef = useRef();
const handleClick = () => {
// 点击按钮 文本框获取焦点
inpRef.current.focus();
}
return(
<div>
<input ref={inpRef} />
<button onClick={handleClick}>Click me</button>
</div>
)
}
forwardRef
ref 本身是不能跨层级捕获和传递的,forwardRef
可以接收父元素的ref信息,转发下去,在父组件中即可直接获取子组件的元素。如下,在父组件点击button后子组件的input获取焦点:
js
import React, { useRef, forwardRef } from 'react'
const Child = forwardRef((props, ref) => {
return (<div>
<input ref={ref} />
</div>)
})
export default function Main() {
const childRef = useRef();
const handleClick = () => {
childRef.current.focus();
}
return(
<div>
<Child ref={childRef} />
<button onClick={handleClick}>focus</button>
</div>
)
}
useImperativeHandle
在父组件中,直接调用子组件的方法,该hook接收三个参数:
- ref: ref 接收forwardRef 传递进来的ref
- createHandle: 返回暴露给父组件的 ref 对象
- deps: 更新ref对象的依赖
jsx
import React, { useRef, forwardRef, useImperativeHandle } from 'react'
const Child = forwardRef((props, ref) => {
const inpRef = useRef();
const focus = () => {
inpRef.current.focus();
}
const changeValue = (value) => {
inpRef.current.value = value;
}
useImperativeHandle(ref, () => ({ focus, changeValue }))
return (<div>
<input ref={inpRef} />
</div>)
})
export default function Main() {
const exposeRef = useRef(null);
const handleFocus = () => {
exposeRef.current.focus();
}
const handleChangeValue = () => {
exposeRef.current.changeValue('Hello World')
}
return(
<div>
<Child ref={exposeRef} />
<button onClick={handleFocus}>InputFocus</button>
<button onClick={handleChangeValue}>ChangeValue</button>
</div>
)
}
useContext
作用: 可以读取和订阅组件中的context
。
useContext(SomeContext)
参数:使用createContext
方法创建的context
,context 本身不包含信息,它只代表你可以提供或从组件中读取的信息类型。
返回值:useContext
为调用组件返回context
的值。它被确定为传递给树中调用组件上方最近的SomeContext.Provider
的value
。如果没有这样的provider
,那么返回值将会是创建context
时赋予的默认值。返回的值始终是最新的。如果context
发生变化,React会自动重新渲染读取context
组件。
js
import React, { useState, useContext, createContext } from 'react'
const TargetContext = createContext(null)
const ChildA = () => {
const num = useContext(TargetContext)
return (<div>
<p>ChildA-{ num }</p>
</div>)
}
const ChildB = () => {
const num = useContext(TargetContext)
return (<div>
<ChildA />
<p>ChildB-{ num }</p>
</div>)
}
export default function Main() {
const [num, setNum] = useState(10)
return(
<TargetContext.Provider value={num}>
<ChildB />
{/* 当num发生变化时,会重新渲染包裹在Context中的所有组件并赋予更新后的值 */}
<button onClick={() => setNum(num * 2)}>update</button>
</TargetContext.Provider>
)
}
HOC
HOC的优点
- 逻辑、组件复用,减少过多的重复代码,提升可读性
- 控制组件的渲染逻辑
- 可代理使用HOC组件的生命周期
属性继承
对被处理组件的props进行代理劫持
js
import React from 'react'
const withCard = (color) => (Component) => {
const PrivateComponent = (props) => {
const style = {
fontSize: '20px',
color
}
return <div style={style}>
{/* 被处理组件的props一定会有一个type属性 */}
<Component {...props} type={ 'hoc' } />
</div>
}
return PrivateComponent;
}
const ChildA = withCard('blue')((props) => {
return (<p>childA--{props.type}</p>)
})
const ChildB = withCard('yellow')((props) => {
return (<p>childB--{props.type}</p>)
})
export default function App() {
return(
<section>
<ChildA />
<ChildB />
</section>
)
}
反向继承
反向继承会返回一个继承了传入组件的类组件,并在render
函数中调用super.render()
。这样做的好处是可以通过高阶组件之间访问到传入组件的this,操作组件中的state和生命周期钩子等等。
js
import React from 'react'
const logProps = (logMap) => {
return (WrappedComponent) => {
const didMount = WrappedComponent.prototype.componentDidMount;
return class PrivateComponent extends WrappedComponent {
componentDidMount() {
if (didMount) {
didMount.apply(this)
}
Object.entries(logMap).forEach(([k, v]) => {
if (document.getElementById(k)) {
console.log(v, this.uname) // Text Message Dane
}
})
}
render() {
return super.render();
}
}
}
}
class Index extends React.Component {
constructor() {
super();
this.uname = 'Dane'
}
render() {
return (
<div>
<p id="text">Hello World</p>
</div>
)
}
}
const LogIndex = logProps({'text': 'Text Message'})(Index)
export default function App() {
return(
<section>
<LogIndex />
</section>
)
}