-
Notifications
You must be signed in to change notification settings - Fork 0
Open
@Kehao
Description
1. React.mixin
React mixin 是通过React.createClass创建组件时使用的,现在主流是通过ES6方式创建react组件,官方因为mixin不好追踪变化以及影响性能,所以放弃了对其支持,同时也不推荐使用。这里简单介绍下mixin。
mixin的原理其实就是将[mixin]里面的方法合并到组件的prototype上。
var logMixin = {
alertLog:function(){
alert('alert mixin...')
},
componentDidMount:function(){
console.log('mixin did mount')
}
}
var MixinComponentDemo = React.createClass({
mixins:[logMixin],
componentDidMount:function(){
document.body.addEventListener('click',()=>{
this.alertLog()
})
console.log('component did mount')
}
})
// 打印如下
// component did mount
// mixin did mount
// 点击页面
// alert mixin
mixin就是将logMixn的方法合并到MixinComponentDemo组件中,如果有重名的生命周期函数都会执行(render除外,如果重名会报错)。
但是由于mixin的问题比较多, 所以被react放弃。
- mixins 引入了不清晰的依赖关系
组件采用了mixins的state和方法,mixins采用了组件的方法,或者mixins又依赖了其他的mixins。这样导致组件和mixins有强耦合的关系,而这些关系不是存在同一个文件中,修改组件或者修改mixins都是非常危险的行为
- mixins 导致命名空间的冲突
- mixins 导致滚雪球般的复杂度
2. 高阶组件
function logTimeHOC(WrappedComponent,options={time:true,log:true}){
return class extends React.Component{
constructor(props){
super(props);
this.state = {
index: 0
}
this.show = 0;
}
componentDidMount(){
options.time&&this.timer = setInterval(()=>{
this.setState({
index: ++index
})
},1000)
options.log&&console.log('组件渲染完成----')
}
componentDidUpdate(){
options.log&&console.log(`我背更新了${++this.show}`)
}
componentWillUnmount(){
this.timer&&clearInterval(this.timer)
options.log&&console.log('组件即将卸载----')
}
render(){
return(<WrappedComponent {...this.state} {...this.props}/>)
}
}
}
class InnerLogComponent extends React.Component{
render(){
return(
<div>我是打印日志组件</div>
)
}
}
// 使用高阶组件`logTimeHOC`包裹下
export default logTimeHOC(InnerLogComponent,{log:true})
这样不仅复用了业务逻辑提高了开发效率,同时还方便后期维护。react里的connect, withRouter都是高阶组件。
export default withRouter(connect(({ login, loading }) => ({ login, loading: loading.models.login }))(Form.create()(Login)))
但也有一些缺陷:
- 高阶组件的props都是直接透传下来,无法确实子组件的props的来源。
- 可能会出现props重复导致报错。
- 组件的嵌套层级太深。
- 会导致ref丢失。
3. React Hook
它不仅仅解决了功能复用的问题,还让我们以函数的方式创建组件,摆脱Class方式创建,从而不必在被this的工作方式困惑,不必在不同生命周期中处理业务。
是目前比较完美的代码封装方式。
import React,{ useState, useEffect } from 'react'
function useLogTime(data={log:true,time:true}){
const [count,setCount] = useState(0);
useEffect(()=>{
data.log && console.log('组件渲染完成----')
let timer = null;
if(data.time){
timer = setInterval(()=>{setCount(c=>c+1)},1000)
}
return ()=>{
data.log && console.log('组件即将卸载----')
data.time && clearInterval(timer)
}
},[])
return {count}
}
export default function LogComponent(){
useLogTime({log:true})
return(
<div>我是打印日志组件</div>
)
}
// 判断是否在视口里面
function isInWindow(el){
const bound = el.getBoundingClientRect();
const clientHeight = window.innerHeight;
return bound.top <= clientHeight + 100;
}
// 加载图片真实链接
function loadImg(el){
if(!el.src){
const source = el.getAttribute('data-sourceSrc');
el.src = source;
}
}
// 加载图片
function checkImgs(className){
const imgs = document.querySelectorAll(`img.${className}`);
Array.from(imgs).forEach(el =>{
if (isInWindow(el)){
loadImg(el);
}
})
}
function useImgLazy(className){
useEffect(()=>{
window.addEventListener('scroll',()=>{
checkImgs(className)
});
checkImgs(className);
return ()=>{
window.removeEventListener('scroll')
}
},[])
}
function App(){
// ...
useImgLazy('lazy-img')
// ...
return (
<div>
// ...
<img className='lazy-img' data-sourceSrc='真实图片地址'/>
</div>
)
}
4.继承
不推荐,但有时更顺手。
Metadata
Metadata
Assignees
Labels
No labels