文章目录
- render-props 模式
- props 方式
- children 方式(推荐)
- Hoc(高阶组件)
- 使用步骤
- 示例
- props 丢失
- 解决方案
- 自定义 hook
- 1.只执行一次
- 2.防抖hook
- 高阶组件与自定义hook有什么区别
- 相同点
- 不同点
React 中代码逻辑复用有三种方式,render-props
, Hoc
,·自定义hooks·
注意: render-props
, Hoc
这两种方式不是新的API,而是利用React自身特点的编码技巧,演化而成的固定模式(写法)
render-props 模式
注意: 并不是该模式叫 render props 就必须使用名为 render 的 prop,实际上可以使用任意名称的 prop
props 方式
封装一个 render-props 模式下的鼠标移动,得到鼠标当前移动位置
// 封装的组件
class Mounse extends React.Component {
state = {
x: 0,
y: 0
}
componentDidMount(){
window.addEventListener('mousemove', this.mouseMove)
}
componentWillUnmount(){
window.removeEventListener("mousemove", this.mouseMove)
}
mouseMove= (e) => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
render(){
renten this.props.render(this.state)
}
}
// 使用
export default function Index() {
return (
<h1>
<Mouns render={(mouse)=>{
return <p>x: { mouse.x }----y: { mouse.y }</p>
}} />
)
}
children 方式(推荐)
// 封装的组件
class Mounse extends React.Component {
state = {
x: 0,
y: 0
}
componentDidMount(){
window.addEventListener('mousemove', this.mouseMove)
}
componentWillUnmount(){
window.removeEventListener("mousemove", this.mouseMove)
}
mouseMove= (e) => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
render(){
renten this.props.children(this.state)
}
}
使用
// 使用
export default function Index() {
return (
<h1>
<Mouns>
{
(mouse)=>{
<p>x: { mouse.x }----y: { mouse.y }</p>
}
}
</Mouns>
)
}
Hoc(高阶组件)
高阶组件使用一个函数,接收要包装的组件,返回一个增强后的组件
使用步骤
- 创建一个函数,以
with
开头 - 指定函数参数,函数参数为一个组件,组件以大写字母开头
- 在函数内创建一个类组件,提供状态逻辑代码,并返回
示例
function WithMounse(Com) {
class Mounse extends PureComponent {
state = {
x: 0,
y: 0
}
componentDidMount(){
window.addEventListener('mousemove',this.handleMonve)
}
componentWillUnmount(){
window.removeEventListener("mousemove", this.handleMonve)
}
handleMonve = e => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
render(){
return <Com {...this.state} />
}
}
return <Mounse />
}
const Foo = props => {
return <p>{props.x}...{props.y}</p>
}
const EndCom = WithMounse(Foo).type
// 调用
class App extends PureComponent {
render() {
return (
<EndCom />
)
}
}
props 丢失
问题示范
由图片可以看出,在高阶组件中传入一个 props 属性 a = 1
在组件里面接收不到,这就是属性丢失
解决方案
在高阶组件封装的时,对props属性再次进行传递
示例
<Com {...this.state} {...this.props} />
function WithMounse(Com) {
class Mounse extends PureComponent {
state = {
x: 0,
y: 0
}
componentDidMount(){
window.addEventListener('mousemove',this.handleMonve)
}
componentWillUnmount(){
window.removeEventListener("mousemove", this.handleMonve)
}
handleMonve = e => {
this.setState({
x: e.clientX,
y: e.clientY
})
}
render(){
return <Com {...this.state} {...this.props} />
}
}
return <Mounse />
}
自定义 hook
hook 是react16.8 的新特性,它可以在你不编写class组件的情况下使用state一级其他的React的特性
通过自定义hook,可以将组件逻辑提取到可重复的函数中
注意:自定义hook 一定以 use 开头,例如 useDebonce
,useQuery
等等
下面是几个自定义 hook 的封装
1.只执行一次
export const useMount = (callback: () => void) => {
useEffect(() => {
callback()
}, [])
}
使用
useMount(()=>{
// 数据请求
})
2.防抖hook
export const useDebonce = <T>(value: T, delay?: number): T => {
const [debounce, setDebounce] = useState(value)
useEffect(()=>{
let timer = setTimeout(()=>{
setDebounce(value)
}, delay)
return ()=> clearTimeout(timer)
},[value, delay])
return debounce
}
使用
const changeValue = '改变所依赖的值'
const Debonce = useDebonce(changeValue, 300)
useEffect(()=>{
console.log('changeValue')
},[Debonce])
高阶组件与自定义hook有什么区别
相同点
- 都是对组件逻辑的封装,达到组件逻辑复用的目的
不同点
- 定义方式不同:高阶组件以
with开头
,自定义hook以use
开头 - 特性不同:高阶组件是类组件中的总结出来的一种编码技巧,自定义hook 是
react16.8
后出来的新特性 - 使用场景不同: 高阶组件一般在函数组件中使用,自定义hook只有函数组件中有
- 返回值不同:高阶组件的返回值是一个组件,自定义hook的返回值可有可无