使用高阶组件来改变样式
有时有一些组件可能只需要很少的一部分state来维护一些很简单的交互, 我们也有充足的理由把这些组件作为可复用的组件.
例子. Carousel组件的交互
例子: 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>
);