使用高阶组件来改变样式

有时有一些组件可能只需要很少的一部分state来维护一些很简单的交互, 我们也有充足的理由把这些组件作为可复用的组件.

例子. Carousel组件的交互

这个高阶组件会持有当前幻灯片的index并且提供前进和回退的功能.

// 高阶组件
import React from 'react'
// 这个高阶组件其实可以被命名的更加通俗易懂, 比如Counter或者Cycle
const CarouselContainer = (Comp) => {
  class Carousel extends React.Component {
    constructor() {
      super();
      this.state = {
        index: 0
      };
      this.previous = () => {
        const { index } = this.state;
        if (index > 0) {
          this.setState({index: index - 1})
        }
      };

      this.next = () => {
        const { index } = this.state;
        this.setState({index: index + 1})
      }
    }

    render() {
      return (
        <Comp
          {...this.props}
          {...this.state}
          previous={this.previous}
          next={this.next}/>
      )
    }
  }
  return Carousel
};
export default CarouselContainer;

使用高阶组件

// 纯UI component
const Carousel = ({ index, ...props }) => {
  const length = props.length || props.children.length || 0;

  const sx = {
    root: {
      overflow: 'hidden'
    },
    inner: {
      whiteSpace: 'nowrap',
      height: '100%',
      transition: 'transform .2s ease-out',
      transform: `translateX(${index % length * -100}%)`
    },
    child: {
      display: 'inline-block',
      verticalAlign: 'middle',
      whiteSpace: 'normal',
      outline: '1px solid red',
      width: '100%',
      height: '100%'
    }
  };

  const children = React.Children.map(props.children, (child, i) => {
    return (
      <div style={sx.child}>
        {child}
      </div>
    )
  });

  return (
    <div style={sx.root}>
      <div style={sx.inner}>
        {children}
      </div>
    </div>
  )
};

// 最后的Carousel组件
const HeroCarousel = (props) => {
  return (
    <div>
      <Carousel index={props.index}>
        <div>Slide one</div>
        <div>Slide two</div>
        <div>Slide three</div>
      </Carousel>
      <Button
        onClick={props.previous}
        children='Previous'/>
      <Button
        onClick={props.next}
        children='Next'/>
    </div>
  )
};

// 我们通过在外面包裹一层container组件来给这个组件带来更多的功能.
export default CarouselContainer(HeroCarousel)

通过保持样式和交互状态的分离, 基于同一个carsousel组件, 我们可以创造任意数量不同的更复杂的carousel组件,

用法

const Carousel = () => (
  <div>
    <HeroCarousel />
  </div>
);

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「IT平头哥联盟」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界

results matching ""

    No results matching ""