Hoc高阶组件

Higher - Order Components:在原有组件基础之上加工后新生成得到的新组件。【高阶组件】

const NewComponent = HOC(YourComponent)

通俗的来讲,高阶组件就相当于手机壳,通过包装组件,增强组件功能。

HOC实现步骤:

  • 创建一个函数

  • 指定函数参数,参数应该以大写字母开头

  • 在函数内部创建一个类组件,提供复用的状态(如有)及逻辑代码,并返回

  • 在该组件中,渲染参数组件,同时将状态通过prop传递给参数组件(可选,如有)

  • 调用该高阶组件方法,传入要增强的组件,通过返回值拿到增强后的组件,并将其渲染到页面

比如,我们想要我们的组件通过自动注入一个版权信息:

import React, { Component, Fragment } from "react";

const withCopyright = (Cmp) => {
    return class Hoc extends Component {
        render() {
            return (
                <Fragment>
                    <Cmp></Cmp>
                    <div>&copy; 2020 千峰教育</div>
                </Fragment>
            );
        }
    };
};

export default withCopyright;

// Fragment是一个伪标签,渲染的时候是不会显示在页面中的,因此也不会影响视图显示

使用方式:

import React, { Component } from "react";
// 引入HOC函数
import Hoc from './Hoc/Hoc_copyright'

class App extends Component {
    render() {
        return (
            <div>
                <h1>网站首页</h1>
            </div>
        );
    }
}

export default Hoc(App);

案例: 

import React, { Component } from "react";
import { Fragment } from "react";
/**
 * 高阶组件: 把组件包装 扩展原有组件的功能
 * 实现步骤
 * 1.创建一个函数
 * 2.函数参数为组件形参
 * 3.在函数内部创建一个类组件,提供**复用**的状态(如有)及逻辑代码,并返回
 * 4.在返回的类组件找中将传入的参数组件进行加工并渲染
 *
 */
class App extends Component {
  render() {
    return <div>App</div>;
  }
}
// 第二步 Cmp 参数 为 组件参数
const WithCopy = (Cmp) => {
  // 第一步 创建一个WithCopy的函数
  return class Hoc extends Component {
    // 第三步 在内部生成一个类组件 并返回
    render() {
      return (
        // 写法一
        // <div>
        //   <Cmp></Cmp>
        //   <div>版权信息</div>
        // </div>
        // 写法二
        <Fragment>
          <Cmp></Cmp>
          <div>版权信息</div>
        </Fragment>
      );
    }
  };
};

const WithColor = (Cmp) => {
  return class Hoc extends Component {
    render() {
      return (
        <div style={{ backgroundColor: "aqua" }}>
          <Cmp></Cmp>
        </div>
      );
    }
  };
};

export default WithColor(WithCopy(App)); // 第四步 进行组件合并

这样只要我们有需要用到版权信息的组件,都可以直接使用withCopyright这个高阶组件包裹即可。

当然,也可以使用ES7的装饰器(ES7的一个新语法,它可以对一些对象进行装饰包装然后返回一个被包装过的对象,可以装饰的对象包括:类,属性,方法等)来实现高阶组件的效果,需要在package.json文件中增加如下配置:

"plugins": [
  [
          "@babel/plugin-proposal-decorators",
          {
              "legacy": true
          }
  ]
]

①默认情况下装饰器语法在react中是不被支持的,如果直接用会报错

Support for the experimental syntax 'decorators-legacy' isn't currently enabled

②开启装饰器的支持(需要配置babel),需要解压react封装在react-scripts项目中配置

git add .
git commit -m xxx
npm run eject

③需要在package.json文件中给babel增加如下配置(加完之后需要重启项目)

"plugins": [
     [
         "@babel/plugin-proposal-decorators",
         {
             "legacy": true
         }
     ]
]

 ④装饰器语法

@方法名

案例:

import React, { Component } from "react";
import { Fragment } from "react";
/**
 * 高阶组件: 把组件包装 扩展原有组件的功能
 * 实现步骤
 * 1.创建一个函数
 * 2.函数参数为组件形参
 * 3.在函数内部创建一个类组件,提供**复用**的状态(如有)及逻辑代码,并返回
 * 4.在返回的类组件找中将传入的参数组件进行加工并渲染
 *
 */

// 第二步 Cmp 参数 为 组件参数
const WithCopy = (Cmp) => {
  // 第一步 创建一个WithCopy的函数
  return class Hoc extends Component {
    // 第三步 在内部生成一个类组件 并返回
    render() {
      return (
        // 写法一
        // <div>
        //   <Cmp></Cmp>
        //   <div>版权信息</div>
        // </div>
        // 写法二
        <Fragment>
          <Cmp></Cmp>
          <div>版权信息</div>
        </Fragment>
      );
    }
  };
};

const WithColor = (Cmp) => {
  return class Hoc extends Component {
    render() {
      return (
        <div style={{ backgroundColor: "aqua" }}>
          <Cmp></Cmp>
        </div>
      );
    }
  };
};

// @  装饰器语法 扩展原有类功能  
@WithColor
@WithCopy
export default class App extends Component {
  render() {
    return <div>App</div>;
  }
}


css-in-js技术

1、简介

CSS-in-JS是一种技术,而不是一个具体的库实现。简单来说CSS-in-JS就是将应用的CSS样式写在JavaScript文件里面,而不是独立为一些css,scss或less之类的文件,这样你就可以在CSS中使用一些属于JS的诸如模块声明,变量定义,函数调用和条件判断等语言特性来提供灵活的可扩展的样式定义。CSS-in-JS在React社区的热度是最高的,这是因为React本身不会管用户怎么去为组件定义样式的问题,而Vue有属于框架自己的一套定义样式的方案。

  • 在js文件中写css就是css-in-js技术

  • 好处:

    • 支持一些js的特性

      • 继承

      • 变量

      • 函数

    • 支持框架的特性

      • 传值特性

styled-components 应该是CSS-in-JS最热门的一个库,通过styled-components,你可以使用ES6的标签模板字符串语法,为需要styled的Component定义一系列CSS属性,当该组件的JS代码被解析执行的时候,styled-components会动态生成一个CSS选择器(比较随意的),并把对应的CSS样式通过style标签的形式插入到head标签里面。动态生成的CSS选择器会有一小段哈希值来保证全局唯一性来避免样式发生冲突。

  • 通过ES6里面的模版字符串形式写css样式(遵循之前css样式代码的写法)

  • 每个样式选择器都会在编译之后自动被添加上一个hash值(全局唯一)

使用styled-components前需要安装,安装的命令如下:

npm i -S styled-components

由于css后期会在模版字符串中编写,默认情况下vscode是没有css样式代码片段的(写样式的时候是没有代码提示的),为了提高css代码在模版字符串中编写的效率,此处强烈建议安装一个vscode的扩展:vscode-styled-components。

在React中写样式的方式一共有:

  • import "xxx.css"

  • styled-components

  • 行内标签style属性

  • index.html中Link标签

  • index.html的style标签

2、定义样式与使用

定义

import styled from "styled-components";
const Title = styled.div`
    font-size: 110px;
    color: pink;
    font-family: 华文行楷;
    background-color: black;
`;
export { Title };

使用

在使用的时候成员会被当作组件去使用(首字母大写)

import React, { Component, Fragment } from "react";
// 就像使用常规 React 组件一样使用 Title
import { Title } from "./assets/style/style";
​
class App extends Component {
    render() {
        return (
            <Fragment>
                <Title>桃之夭夭,灼灼其华。</Title>
            </Fragment>
        );
    }
}
​
export default App;

3、样式继承

styled-components中也可以使用样式的继承,其继承思想与react的组件继承相似:

  • 继承父的样式

  • 重载父的样式

样式继承
import styled from "styled-components";

const Button = styled.button`
    font-size: 20px;
    border: 1px solid red;
    border-radius: 3px;
`;
// 一个继承 Button 的新组件, 重载了一部分样式
// 继承会合并与父的样式,但是如果遇到样式冲突(相同),会以自己的为准
const Button2 = styled(Button)`
    color: blue;
    border-color: yellow;
`;

export { Button, Button2 };

 使用

import React, { Component, Fragment } from "react";

import { Button, Button2 } from "./assets/style/style";

class App extends Component {
    render() {
        return (
            <Fragment>
                <Button>我是第1个按钮</Button>
                <Button2>我是第2个按钮</Button2>
            </Fragment>
        );
    }
}

export default App;

案例(基础样式案例):

import React, { Component } from "react";
import "./assets/css/App.css"; // 引入外部样式
// 引入 style-component
import styled from "styled-components";

// 方法三 
const LineOne = styled.div`
  color: aqua;
`;
export default class App extends Component {
  render() {
    return (
      <div>
        {/* 方法一 style 属性 */}
        <div style={{ fontSize: 24 + "px", color: "aqua" }}>第一行</div>
        {/* 方法二 外部引入  若是外部子组件类名相同 则样式相同 不存在作用域限制 存在污染情况*/}
        <div className="lineOne">第二行</div>
        {/* 方法三 安装 styled-components  在组件内部使用  存在隔离  解决全局样式污染*/}
        <LineOne>
          <div>第二行</div>
        </LineOne>
      </div>
    );
  }
}

 

4、属性传递

属性传递:样式值的动态传参(组件传值)

基于css-in-js的特性,在styled-components中也允许我们使用props(父传子),这样一来,我们可以对部分需要的样式进行传参,很方便的动态控制样式的改变。

属性传递(JS中接收)
import styled from "styled-components";

// 参数传递
const Input = styled.input`
    color: ${(props) => props.inputColor || "red"};
`;

export { Input };
动态传递参数
import React, { Component, Fragment } from "react";

import { Input } from "./assets/style/style";

class App extends Component {
    render() {
        return (
            <Fragment>
                <Input defaultValue="are you ok?" inputColor="blue"></Input>
            </Fragment>
        );
    }
}

export default App;

案例(styled-components):

import React, { Component } from "react";
// 引入 style-component
import styled from "styled-components";

// 方法三 
const LineOne = styled.div`
  color: aqua;
`;
// 1.样式继承
const Line4 = styled(LineOne)`
  background-color: blue;
`;

// 属性传递
const MyColor = styled.div`
  color:  ${(props) => props.color || "red"};
`;
export default class App extends Component {
  render() {
    return (
      <div>
        {/* 方法三 安装 styled-components  在组件内部使用  存在隔离  解决全局样式污染*/}
        <LineOne>
          <div>第二行</div>
        </LineOne>
        {/*  styled-components高级写法 */}
        {/* 1.样式继承 */}
        <Line4>
          第四行
        </Line4>
        {/* 2.动态传递参数 */}
        <MyColor color="pink">
          第五行
        </MyColor>
      </div>
    );
  }
}

路由预热

1、介绍

React Router官网:Home v6.21.1 | React Router

使用用React Router前需要先进行安装:

npm i react-router-dom@5.3.0

React Router现在的主版本是5,思想:一切皆组件

2、路由的使用

2.1、相关组件

如前面介绍里说的,自Router 4之后的思想是一切皆组件,所以在正式开始学习React路由前需要先对几个组件要有所掌握:

  • Router组件(别名,真实是不存在的,为了简写路由模式的组件名称):包裹整个应用(单个具体的组件/根组件),一个React应用只需要使用一次

    • 注意:在react中,不存在类似于vue的路由配置文件,对于前端路由模式的选择,我们可以通过该组件完成

    • Router类型: HashRouter和BrowserRouter

      • HashRouter: 使用URL的哈希值实现 (localhost:3000/#/first)

      • BrowserRouter:使用H5的history API实现(localhost:3000/first)

    • 区别

      • 两者在开发阶段,除了地址栏上的表现形式不一样以外,其它没区别

      • 两者在生产阶段,hash路由可以直接上生产,无需做任何配置,而history模式则上生产需要配置的,配置服务器环境,否则项目是不能刷新的,一刷新会404

  • Link组件:用于指定导航链接(a标签)就是做声明式导航的(类似于vue中的router-link组件

    • 最终Link会编译成a标签,而to属性会被编译成 a标签的href属性

  • Route组件:指定路由展示组件相关信息(组件渲染)【路由规则】{path: xx,component:xxx}

    • path属性:路由规则,这里需要跟Link组件里面to属性的值一致

    • component属性:展示的组件

    • 语法:<Route path="路径" component={组件}></Route>

    • 该组件除了具备定义路由规则功能外,还有类似于vue中router-view的功能

各个组件之间的关系

注意:LinkRoute组件必须被Router组件给包裹,否则报错。

案例:

import React, { Component } from "react";
/**
 * React-router 中一切皆组件
 * 跳转标签 Link to url 地址
 * NavLink 跳转标签 会有一个选择css类名
 * Route 渲染容器 切换的组件渲染显示的地方 路由映射关系
 * Router BrowserRouter 历史路由
 *        HashRouter hash路由
 */
import { Link, Route ,NavLink} from "react-router-dom";

import pageA from "./pages/pageA";
import pageB from "./pages/pageB";

export default class App extends Component {
  render() {
    return (
      <div>
        <ul>
          <li>
            <Link to="/a">去A页面</Link>
          </li>
          <li>
            <NavLink to="/b">去B页面</NavLink>
          </li>
        </ul>
        <hr />
        <Route path="/a" component={pageA}></Route>
        <Route path="/b" component={pageB}></Route>
      </div>
    );
  }
}

Logo

前往低代码交流专区

更多推荐