如何用Ramda或Monad改写React条件渲染逻辑?
用Ramda或Monad实现React条件渲染逻辑
我正在把一个应用的部分代码Ramda化,目前完成了90%,只剩最后一个问题:将React函数组件里的条件渲染逻辑用Ramda或Monad实现。之前原型阶段我已经能用Ramda/Monad改写简单if语句,但React组件返回多渲染结果的特性,让函数式纯特性不好发挥。
需要改写的示例代码:
// rewrite in Ramda if (status === 'loading' || isUpdating) { return <PageSpinner /> } if (postError || isUpdateError) { return <ErrorComp /> }
请问如何用Ramda或Monad实现上述条件渲染逻辑?
测试步骤:
git clone https://github.com/muratkeremozcan/tour-of-heroes-react-cypress-ts.git cd tour-of-heroes-react-cypress-ts yarn cy:open-ct # run the test BoysList
解决方案
方案1:使用Ramda的cond函数(最直接的函数式写法)
Ramda的cond函数专门用于处理多分支条件判断,它接收一组[条件校验函数, 结果返回函数]的数组,会依次校验条件,返回第一个满足条件的结果函数的执行值,完全符合纯函数的要求。
import { cond, always, T } from 'ramda'; // 先定义正常渲染的内容(如果有的话) const renderNormalContent = ({ boy }) => ( <div> {/* 这里放你的正常渲染内容 */} </div> ); // 用cond串联所有渲染分支 const renderStatus = cond([ // 分支1:加载中或更新中 → 返回加载组件 [({ status, isUpdating }) => status === 'loading' || isUpdating, always(<PageSpinner />)], // 分支2:存在错误 → 返回错误组件 [({ postError, isUpdateError }) => postError || isUpdateError, always(<ErrorComp />)], // 默认分支:返回正常渲染内容(T表示永远为真的条件) [T, renderNormalContent] ]); // 在组件中调用 return renderStatus({ status, isUpdating, postError, isUpdateError, boy });
如果正常渲染内容不需要单独封装,也可以直接用always传入JSX:
const renderStatus = cond([ [({ status, isUpdating }) => status === 'loading' || isUpdating, always(<PageSpinner />)], [({ postError, isUpdateError }) => postError || isUpdateError, always(<ErrorComp />)], [T, always(<div>正常内容</div>)] ]);
方案2:使用Monad(Either)实现
如果想更贴合Monad的函数式风格,可以用Either类型区分"异常状态(加载/错误)"和"正常状态",通过fold方法统一提取渲染结果:
import { Either, left, right } from 'ramda-fantasy'; // 可使用成熟的Monad库,比如ramda-fantasy // 构建状态对应的Either实例 const getRenderable = ({ status, isUpdating, postError, isUpdateError, boy }) => { if (status === 'loading' || isUpdating) { return left(<PageSpinner />); // 异常状态放入left分支 } if (postError || isUpdateError) { return left(<ErrorComp />); // 异常状态放入left分支 } return right(renderNormalContent({ boy })); // 正常状态放入right分支 }; // 在组件中提取Either的值 return getRenderable({ status, isUpdating, postError, isUpdateError, boy }).fold( (fallback) => fallback, // 处理left分支:加载/错误组件 (content) => content // 处理right分支:正常内容 );
内容的提问来源于stack exchange,提问作者Murat Ozcan
相关产品推荐
相关产品推荐

