React.cloneElement

555 阅读2分钟

原来:

src\renderer\pages\index\index.tsx

const Index: React.FC = () => {
    ...
  return (
    <Header hasCountDown={false}/>
      <div className={style.con} >
            ...
      </div>
    <Footer showBackBtn={false}/>
  );
};

src\renderer\components\Layout\Header.tsx

import React from 'react';
import { Layout } from 'antd';
import style from './style.scss';
import { getUserAsync } from '../../user';
import CountDown from '../CountDown';
import Clock from './Clock';
import { hideCode } from 'util/tools';

const AntHeader = Layout.Header;

export interface MyParams {
  hasCountDown?: boolean;
}

//从 props里解构出 hasCountDown,赋默认值为 true。如果有传入值,以传入值为准
const Header: React.FC<MyParams> = ({ hasCountDown = true, }) => {
  const user = getUserAsync();

  const loginOut = () => {
    console.log('111')
  };
  return (
    <AntHeader className={style.header}>
      <div className={style.clock}>
        <Clock />
      </div>
      {user ? (
        <div className={style.countDown}>
          {hasCountDown ? <CountDown onCountDown={() => loginOut()} /> : null}
          <div className={style.user}>
            {/* 导入并使用hideCode方法。除了姓,其他用*表示 */}
            {user && hideCode(user.name, 1, 0)}
            ,您好!
          </div>
        </div>
      ) : null}
    </AntHeader>
  );
};

export default Header;

src\renderer\components\Layout\Footer.tsx

ReactElement、ReactNode以及JSX.Element

ReactNode是一种联合类型(Union Types),可以是string、number、ReactElement、{}、boolean、ReactNodeArray

import React from 'react';
import { Layout } from 'antd';
import style from './style.scss';
import { useHistory } from 'react-router-dom';

const AntFooter = Layout.Footer;

export interface MyParams {
  showBackBtn?: boolean;
  leftBtn?: {
    text: string;
    onClick: () => void;
    icon: React.ReactNode;
  };
}
const Footer: React.FC<MyParams> = (props) => {
  let {
    showBackBtn = true,
    leftBtn = {
      text: '上一步',
      onClick: () => {
        history.goBack();
      },
      icon: null,
    },
  } = props;
  let history = useHistory();

  function unLogin() {
    window.xxx()
      .then(function () {
        console.log('');
      })
      .catch(() => {});
  }

  return (
    <AntFooter className={style.footer}>
      <div className={style.container}>
          <div className={style.leftBox}>
            {showBackBtn && (
              <div className={style.lastPage} onClick={leftBtn.onClick}>
                {leftBtn.text == '上一步' && (
                  <div className={style.lastImg}></div>
                )}
                <div className={style.lastText}>
                  {leftBtn.icon && leftBtn.icon}
                  {leftBtn.text}
                </div>
              </div>
            )}
          </div>
          <div onClick={unLogin}>111</div>
      </div>
    </AntFooter>
  );
};

export default Footer;

克隆:

src\renderer\components\PageWrapper\index.tsx

剩余参数rest ES6 的扩展运算符

ES6中扩展运算符的8种用法

import React from 'react'
import { Footer, Header } from '@/renderer/components/Layout';
import { MyParams as FooterProps } from '@/renderer/components/Layout/Footer';
//使用 as 起别名
import { MyParams as HeaderProps } from '@/renderer/components/Layout/Header';

type PageWrapper = {
  children: JSX.Element;
  haderProps?: HeaderProps;
  footerProps?: FooterProps;
  [key: string]: any;
};

//children是使用本 PageWrapper组件包裹了后,其中的 jsx元素
const PageWrapper: React.FC<PageWrapper> = ({ children, haderProps, footerProps, contentClassName, ...rest }) => {
  //...rest 把参数列表中剩余的参数收集到 rest这个数组中
  return (
    <>
    // ...haderProps 使用扩展运算符拷贝对象?
      <Header {...haderProps} />
      <div className={contentClassName} style={{ height: window.innerHeight - (112 + 163), overflow: 'auto' }}>
        {
        //将使用本PageWrapper组件包裹了后其中的jsx元素克隆过来,即用了PageWrapper组件的children
          React.cloneElement(children, rest)
        }
      </div>
      <Footer {...footerProps} />
    </>
  )
}

export default PageWrapper

react之React.cloneElement()

React.cloneElement()接收三个参数,第一个参数是要克隆的目标,接收一个ReactElement,可以是真实的dom结构 也可以是自定义的。第二个参数返回旧元素的props、key、ref,可以添加新的props。第三个是props.children,不指定时 默认展示克隆过来的子元素;如果指定,会覆盖调用克隆组件时里面包含的元素,即克隆目标(第一个参数)

src\renderer\pages\index\index.tsx

import React from 'react';
import PageWrapper from '@/renderer/components/PageWrapper';

import yygh from './image/yyghx.png';
import { getIsLogin } from '../../user';
import { useHistory } from 'react-router-dom';

import style from './index.module.css';

const Index: React.FC = () => {
  let history = useHistory();

  async function handleClick(path) {
    let isLogin = await getIsLogin();
    if (isLogin) {
        history.push(path);
    } else {
      history.push('/loginNew', {
        from: path,
      });
    }
  }

  return (
    <PageWrapper footerProps={{ showBackIndexBtn: false, showBackBtn: false }} haderProps={{ hasCountDown : false}}>
      <div className={style.con} >
        <div className={style.wapper}>
          <div className={style.item} onClick={() => handleClick('/organList/1')}>
            <img src={yygh} />
          </div>
        </div>
      </div>
    </PageWrapper>
  );
};

export default Index;

将方法进行封装

src\util\tools.ts

export function hideCode(str, frontLen, endLen) {
  var len = str.length - frontLen - endLen;
  if(len < 0) return str
  var xing = '';
  for (var i = 0; i < len; i++) {
    xing += '*';
  }
  return str.substring(0, frontLen) + xing + str.substring(str.length - endLen);
}