(HP)react日常开发技巧

高级特性

1,protals(传送门):将子组件渲染到父组件之外。

实例场景:父组件的儿子是<Modal>组件,使用fixed定位虽然样式看着是在父组件之外了,但是打开控制台查看元素,Modal相关的html还是嵌套在id='App'里面。由于fixed定位的元素最好是直接放到body里具有更好的兼容性,所以需要使用protals让modal渲染到body下:

import ReactDom from 'react-dom';

class Test extends from React.component{
 
   render(){
    return  ReactDom.createPortal(<div className="modal">这是一个模态框</div>, document.body)
    }
}

常用场景:

fixed浏览器兼容性,父组件z-index太小,父组件设置了overflow:hidden 

2,context:多层级组件传值

场景:使用props层层传递太啰嗦,使用redux太繁重。

那么可以选择使用context或者recoil

// A.jsx
const ThemeContext = React.creatContext('light')

class A extends React.Component{
  this.state ={ theme: ''}

   render(){
    <ThemeContext.Provider value={this.state.theme} >
        <B />
        <button  onClick={()=>setState({val:'hh'})} ></button>
    </ThemeContext.Provider>
 }
}

// B.jsx

class B extends React.Component{
   render(){
    <div>
        <C />
     </div>
 }
}

// C.jsx(class组件)
 
class C extends React.Component{
   const { theme }= this.context;
   static contextType = ThemeContext 
   render(){
    <div>
        {theme}
     </div>
 }
}

C.contextType=ThemeContext // 如果不这样写,需要在C组件中将注释打开


// C.jsx (函数组件)
function C (){
return <ThemeContext.Consumer> {theme=>theme} </ThemeContext.Consumer>
}

3,高阶组件

多个组件共享一个方法(工厂模式)。一个函数:将一个组件包装好再返回,并赋予给它新的属性或方法,类似装饰器。

使用场景:同一个页面的两个组件都需要用到鼠标滚动获取坐标的方法,又不想在每个组件里写两套相同的方法。

// HOC.tsx
function HOC(component){

const HOCcomponent = ()=>{
  const [res,setRes]=useState();
  const handleMove = (e)=>{
        setRes({x:e.clientX,y:e.clientY};
  }
  return <div onMouseMove={handleMove}> 
               <component mouse={res} {...props} />
         </div>
}

return HOCcomponent
}

4,react合成事件

onClick = (e)=>e.target.scrollTop,类似click等dom的原生事件,在react中被重写了一遍。

合成事件 = 事件注册、事件的合成、事件冒泡、事件派发

为什么要重写一遍:
抹平不同浏览器API的差异,方便跨平台
利用事件委托机制,简化dom事件处理逻辑,减小内存开销

react17之前和之后的区别:
react17之前事件是委托到document的,react18事件是委托到root上的

为什么18要更改委托点:
以下的代码,react17不会展示<div>看见我了</div>,react18会展示。

const [visible,setVisible] = useState(false);
const handleClick=(e)=>{
e.stopPropagation(); // react17无效
   setVisible(true);
}

useEffect(()=>{
   document.addEventListener('click',()=>{
   setVisible(false)
})


<div id='root'>
  <button onClick={handleClick}>点击</button>
</div>

{
visible?<div>看见我了</div>:null
}

原因:react虽然是合成事件但是也是基于事件委托的,所以会有事件冒泡。先执行了handleClick,react准备阻止往上冒泡,却发现,本次的click事件已经绑定到document上了,阻不阻止都是再同一个层级了,所以这个时候document还是能监听到click事件,就是stop失败。

于是react18给合成事件的事件委托到root根元素上,冒泡到root的时候stop,就不会冒泡到document了。

<html>.    // docuemnt
   <div id="roor"><./div>. // 根元素
</html>

5,batchUpdate机制

顺序执行setState({a: 123}),setState({b: 234})会被合并为一次更改state,但是setState({a: 123}),setState({a: 345})不会被合并为一次,而是两次。batchUpdate就是为了减少不必要的state刷新

6,react事务机制

7,react fiber

性能优化

1,异步加载组件:

组件比较大import()或者路由懒加载React.Lazy,React.Suspense

import():正常的组件会随着整个项目打包成一个MD5.js的文件,但是异步加载的组件会单独打包成一个md5.js文件

React.Lazy():相当于一个构造函数,将引入的组件作为输入,封装后输出一个异步的组件

React.Suspense

const Dom = React.lazy(()=>import('../bigComponent')
 
class App extends from React.component{
   render(){
    return <React.Suspense fullback={<div>...loading</div>}>
               <Dom />
    </React.Suspense>
  }
}

2,scu

针对class组件使用shouldComponentUpdate,如果只是进行浅层比较可以使用PureComponent。

针对函数组件可以使用memo(配合useMemo,useCallback使用),如果浅层比较,memo函数第二个参数可以省略,如果深层比较第二个参数可以传一个类似shouldComponentUpdate那样的函数。
比如以下结构代码:

// index.tsx
const Index=()=>{
const [val,setVal]=useState(1);
const [b,setb]=useState('hh');
const add = ()=>setVal(val+1);
const callbackFn = ()=>alert('hi');
return <div>
  <button onClick={add}>按钮{val}</button>
  <B b={b} callbackFn={handle} />
</div>
}

// B.tsx
const B = (b,callbackFn)=>{
console.log('我又被执行了一遍,这就是刷新了这个组件')
return <div>
  {b}
</div>
}
export default(B);

每次点击按钮B组件都会打印那句话,这就说明B组件的代码又被执行了一遍进行重复渲染。为了解决这个重复渲染,变量用useMemo封装起来,函数用useCallback封装起来

// index.tsx
const Index=()=>{
const [val,setVal]=useState(1);
const [b,setb]=useState('hh');
const add = ()=>setVal(val+1);

const bprops = useMemo(()=>b,[b]);
const callbackFn = useCallback(()=>alert('hi'),[]);

return <div>
  <button onClick={add}>按钮{val}</button>
  <B b={b} callbackFn={handle} />
</div>
}

// B.tsx
const B = (b,callbackFn)=>{
console.log('我又被执行了一遍,这就是刷新了这个组件')
return <div>
  {b}
</div>
}
export default(B);

// 如果想要深层比较可以这样写
export default(B,isEqual);
function isEqual(preProps,nextProps){
 if(preProps.b===nextProps.b)return false;
return true;
}

hooks的优势

1,class组件太大很难拆分

2,同一个方法需要分散到不同的生命周期中(事件监听的绑定和解绑)

3,复用逻辑复杂,HOC,Render props

注意点:

1,react hooks必须在最外层执行逻辑,因为它是严格依赖执行顺序的,如果在函数中执行碰到了类似if函数等其他语句,react向存储中拿值可能拿到了别的state的值。

react生态

分类:初始化工具 ,路由,样式,基础组件,功能组件,状态管理,构建工具,代码检查工具

初始化工具:create-react-app、react-app-rewired提供拓展能力,国内umi和dva,如果是开发组件库推荐create-react-library,如果是大规模组件开发使用storybook

路由:react-router

样式:style-components,emotion

基础组件:antd

功能组件:react-dnd、react-draggable拖拽,video-react播放视频,react-pdf-viewer查看pdf,react-window和react-virtualized用于长列表问题

状态管理:recoil,react-easy-state

构建工具:webpack,vite,rollup,esbuild

代码检查工具:代码规范检查eslint,编写代码测试jest,enzyme,react-testing-library,react-hooks-testing-library

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值