这是我参与「第五届青训营 」伴学笔记创作活动的第 16 天
实现
import * as React from 'react';
export type SizeType = 'small' | 'middle' | 'large' | undefined;
const SizeContext = React.createContext<SizeType>(undefined);
export interface SizeContextProps {
size?: SizeType;
children?: React.ReactNode;
}
export const SizeContextProvider: React.FC<SizeContextProps> = ({ children, size }) => (
<SizeContext.Consumer>
{originSize => (
<SizeContext.Provider value={size || originSize}>{children}</SizeContext.Provider>
)}
</SizeContext.Consumer>
);
export default SizeContext;
创建一个 Context 对象,当 React 渲染一个订阅了这个 Context 对象的组件,这个组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值。
Context.Consumer
<SizeContext.Consumer>
{originSize => (
// ...
)}
</SizeContext.Consumer>
这种方法需要一个函数作为子元素(function as a child)。这个函数接收当前的 context 值,并返回一个 React 节点。传递给函数的
value值等价于组件树上方离这个 context 最近的 Provider 提供的value值。如果没有对应的 Provider,value参数等同于传递给createContext()的defaultValue。
使用
确定props类型
export interface TabsProps {
className?: string,
style?: CSSProperties,
size: SizeType // 'small' | 'middle' | 'large' | undefined;
//....
}
编写内容
const Tabs: React.FC<TabsProps> = (props) => {
const {
size:propSize
} = props
return (
<SizeContext.Consumer>
{
contextSize => {
const size = propSize !== undefined ? propSize : contextSize;
return(
<div className={`${prefixCls}-${size}`}></div>
)
}
}
</SizeContext.Consumer>
)
}
组件具有多种状态,${prefixCls}-${size}这种写法对现在的情景是没有问题的,但是出现隐藏和显示两种状态的是否,我们可能会使用的到三元表达式等,这样让className变得难以阅读
所以,我们选择安装依赖classnames来处理该问题:
let buttonType = 'primary';
classNames({ [`btn-${buttonType}`]: true }); // btn-primary
classNames('foo', 'bar'); // => 'foo bar'
classNames('foo', { bar: true }); // => 'foo bar'
classNames({ 'foo-bar': true }); // => 'foo-bar'
classNames({ 'foo-bar': false }); // => ''
classNames({ foo: true }, { bar: true }); // => 'foo bar'
classNames({ foo: true, bar: true }); // => 'foo bar'
// lots of arguments of various types
classNames('foo', { bar: true, duck: false }, 'baz', { quux: true }); // => 'foo bar baz quux'
// other falsy values are just ignored
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'
编写样式
@tab-prefix-cls: ~'@{romantic-prefix}-tabs';
.@{tab-prefix-cls} {
&-small {
> .@{tab-prefix-cls}-nav {
.@{tab-prefix-cls}-tab {
padding: @tabs-horizontal-padding-sm;
font-size: @tabs-title-font-size-sm;
}
}
}
&-large {
> .@{tab-prefix-cls}-nav {
.@{tab-prefix-cls}-tab {
padding: @tabs-horizontal-padding-lg;
font-size: @tabs-title-font-size-lg;
}
}
}
}