闽公网安备 35020302035485号
const CoinFlip = () => Math.random() < 0.5 ? <div>Heads</div> : <div>Tails</div>;事实证明,模仿掷硬币比你想象的要容易得多,所以你可以自豪地分享成果。你得到了回复,“这真的是太棒了!请更新那些显示很酷的硬币的图片好么?” 没问题!
const CoinFlip = () =>
Math.random() < 0.5 ? (
<div>
<img src=”/heads.svg” alt=”Heads” />
</div>
) : (
<div>
<img src=”/tails.svg” alt=”Tails” />
</div>
);
很快,他们会在营销材料中使用你的 <CoinFlip /> 组件,来向人们演示你的新功能有多么炫酷。“我们想在博客上发表文章,但是我们需要标签 'Heads' 和 'Tails',用于 SEO 和其他事情。” 哦,天啊,或许我们需要在商城网站中添加一个标志? const CoinFlip = (
// 堆代码 duidaima.com
// We’ll default to false to avoid breaking the applications
// current usage.
{ showLabels = false }
) =>
Math.random() < 0.5 ? (
<div>
<img src=”/heads.svg” alt=”Heads” />
{/* Add these labels for the marketing site. */}
{showLabels && <span>Heads</span>}
</div>
) : (
<div>
<img src=”/tails.svg” alt=”Tails” />
{/* Add these labels for the marketing site. */}
{showLabels && <span>Tails</span>}
</div>
);
后来,出现了一个需求。“我们想知道你能否只给 APP 里的 <CoinFlip /> 添加一个重掷硬币的按钮?” 事情开始变得糟糕,以致于我不敢再直视 Kent C. Dodds 的眼睛。 const flip = () => ({
flipResults: Math.random()
});
class CoinFlip extends React.Component {
static defaultProps = {
showLabels: false,
// We don’t repurpose `showLabels`, we aren’t animals, after all.
showButton: false
};
state = flip();
handleClick = () => {
this.setState(flip);
};
render() {
return (
// Use fragments so people take me seriously.
<>
{this.state.showButton && (
<button onClick={this.handleClick}>Reflip</button>
)}
{this.state.flipResults < 0.5 ? (
<div>
<img src=”/heads.svg” alt=”Heads” />
{showLabels && <span>Heads</span>}
</div>
) : (
<div>
<img src=”/tails.svg” alt=”Tails” />
{showLabels && <span>Tails</span>}
</div>
)}
</>
);
}
}
很快就有同事找到你。“嗨,你的 <CoinFlip /> 性能太棒了!我们刚接到任务要开发新的 <DiceRoll /> 特性,我们希望可以重用你的代码!” 新骰子的功能: const flip = () => ({
flipResults: Math.random()
});
class CoinFlip extends React.Component {
state = flip();
handleClick = () => {
this.setState(flip);
};
render() {
return this.props.children({
rerun: this.handleClick,
isHeads: this.state.flipResults < 0.5
});
}
}
这个组件是无头的,因为它没有渲染任何东西,它期望当它在处理逻辑的时,各种 consumers 完成视觉表现。因此 APP 代码看起来应该是这样的: <CoinFlip>
{({ rerun, isHeads }) => (
<>
<button onClick={rerun}>Reflip</button>
{isHeads ? (
<div>
<img src=”/heads.svg” alt=”Heads” />
</div>
) : (
<div>
<img src=”/tails.svg” alt=”Tails” />
</div>
)}
</>
)}
</CoinFlip>
商场站点代码: <CoinFlip>
{({ isHeads }) => (
<>
{isHeads ? (
<div>
<img src=”/heads.svg” alt=”Heads” />
<span>Heads</span>
</div>
) : (
<div>
<img src=”/tails.svg” alt=”Tails” />
<span>Tails</span>
</div>
)}
</>
)}
</CoinFlip>
这很好不是么!我们把逻辑与视觉表现完全解耦!这给我们视觉上带来了很大的灵活性!我知道你正在思考什么......你这小笨蛋,这不就是一个渲染属性么? const run = () => ({
random: Math.random()
});
class Probability extends React.Component {
state = run();
handleClick = () => {
this.setState(run);
};
render() {
return this.props.children({
rerun: this.handleClick,
// By taking in a threshold property we can support
// different odds!
result: this.state.random < this.props.threshold
});
}
}
利用这个无头组件,我们在没有对 consumer 进行任何更改对情况下,交换的实现: const CoinFlip = ({ children }) => (
<Probability threshold={0.5}>
{({ rerun, result }) =>
children({
isHeads: result,
rerun
})}
</Probability>
);
现在我们的同事可以分享我们的 <Probability /> 模拟程序机制了! const RollDice = ({ children }) => (
// Six Sided Dice
<Probability threshold={1 / 6}>
{({ rerun, result }) => (
<div>
{/* She was able to use a different event! */}
<span onMouseOver={rerun}>Roll the dice!</span>
{/* Totally different interface! */}
{result ? (
<div>Big winner!</div>
) : (
<div>You win some, you lose most.</div>
)}
</div>
)}
</Probability>
);
非常干净,不是么?分离原则:将策略与机制分离,将接口和引擎分离 —— Eric S. Raymond。
2.我们的界面改变的频率多快?同一机制会有多个接口么?