高阶组件

47 阅读2分钟

关于高阶组件的一点思考:

很喜欢用高阶组件这种形式 高阶组件和高阶函数:本质上都是对输入的函数或者组件在不改变原输入函数(或组件)的前提下,对一个功能(或ui)的增强

UI:这是为了增加一个label,比较简单

export const withLabel = (Component: React.FunctionComponent<any>) => (props: Record<string, any>) => {
 const { label, ...otherProps } = props;
 return (
   <div style={{ display: 'flex' }}>
     <LabelComponent label={label} />
     <Component {...otherProps} />
   </div>
 );
};
export const withHiddenStatus = (Component: React.FunctionComponent<any>) => (props: Record<string, any>) => {
 const { hidden, ...otherProps } = props;
 if (hidden === true) {
   return <div></div>;
 }
 return <Component {...otherProps} />;
};

这个高阶组件是为了给原有组件添加协议,起作用是给传入组件的props注入一个ui和一个检测函数,在尽可能少的改变原有组件的前提下增强起隐私协议功能,有的页面是公用的,但是一个页面有好几个地址,只有规定地址的页面才使用该协议

import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
// import { makeAutoObservable } from 'mobx'
import { observer } from 'mobx-react-lite';
import st from './index.scss';
import cn from 'classnames';
import Wearning from './Wearning';
import { CONTRACT_TIPS_SHORT, HREF } from './const';
import CheckedBox from './CheckedBox';


function PrivacyAgreement({
 check,
 setCheck,
 openWearning,
 wearningText,
 text1 = '我已阅读并同意',
 text2 = CONTRACT_TIPS_SHORT,
}) {
 const turnCheck =  ()=>setCheck(!check);
 return (
     <>
         <div
             className={cn({
                 [st.box]: true,
                 'privacyAgreement-margin': true
             })}
         >
             {!check ? (
                 <div
                     className={cn({
                         [st.checkBox_common]: true,
                         [st.checkBox]: true
                     })}
                     onClick={turnCheck}
                 ></div>
             ) : (
                 <div
                     className={cn({
                         [st.checkBox_common]: true,
                         [st.on]: true
                     })}
                     onClick={turnCheck}
                 >
                     <CheckedBox />
                 </div>
             )}
             <span className={st.text1}>{text1}</span>
             <a
                 href={HREF}
                 target="_blank"
                 rel="noreferrer"
                 className={st.text2}
             >
                 {text2}
             </a>
             <div className={st.wearning}>
                 <Wearning
                     openWearning={openWearning}
                     wearningText={wearningText}
                 />
             </div>
         </div>
     </>
 )
}

export const withPrivacyAgreement = (Components, config={}) => {
 const wearningText = "请勾选同意"+`${config.text2||CONTRACT_TIPS_SHORT}`
 const time = config?.time || 3000;
 const defaultPagePath = [
  '/xxx/1.html',
  '/xxx/2.html',
  '/xxx/3.html',
  '/xxx/4.html',
  '/xxx/5.html',
  '/xxx/6.html',
  '/xxx/7.html'

 ];
 const display_name = config?.displayName || 'privacyAgreement';
 const getPreFixName = (config,key)=>config?.displayName?config.displayName+`_${key}`:key;
 const before_submit = getPreFixName(config,'beforeSubmit');
 const getPA = () => {
   const pathName = window.location.pathname;
   return !!(config?.hasShow || defaultPagePath.includes(pathName));
 };
 const before_setCheck =  getPreFixName(config,'setCheck');
 const display_check = getPreFixName(config,'check');

 return (props) => {
   const hasPA = useRef(getPA());
   const [check, setCheck] = useState(false);
   const [openWearning, setOpenWearning] = useState(false);
   const beforeSubmit = useCallback(() => {
     if (!hasPA.current) return true;
     if (check) return true;
     setOpenWearning(true);
     setTimeout(() => {
       setOpenWearning(false);
     }, time);
     return false;
   }, [check]);

   if (!hasPA.current)
     return (
       <Components
         {...props}
         {...{
           [before_setCheck]: () => {},
           [display_name]: null,
           [before_submit]: () => true,
         }}
       />
     );
   const privacyAgreement = useMemo(
     () => (
       <PrivacyAgreement
         check={check}
         setCheck={setCheck}
         {...config}
         openWearning={openWearning}
         wearningText={wearningText}
         time={time}
       />
     ),
     [check, openWearning, wearningText, time],
   );


   const _props = {
     ...props,
     [display_check]:check,
     [before_setCheck]:setCheck,
     [display_name]:privacyAgreement,
     [before_submit]:beforeSubmit,
   };
   return <Components {..._props} />;
 };
};

总结:网上总说现在是函数组件了 不再使用class组件,就可以不用高阶组件,但是我认为 不管是对类还是函数组件来讲, 高阶组件其本质是一种思想,是装饰者模式的一种实践,和高阶函数是一样的,不论是不是函数组件还是累组件都可以使用