如何在React/Preact中传递条件子元素(即<If>组件)
这个问题我太熟了——很多人第一次写条件渲染的Wrapper组件都会踩这个坑!核心痛点在于:不管SomeWrapper内部要不要渲染子元素,JSX里的子元素表达式都会先执行。所以当condition不成立时,this.may.not.exist.unless.condition是undefined,调用.map()直接就会抛错。
下面给你几种实用的解决方案,按推荐程度排序:
1. 让Wrapper接收函数作为子元素(最优雅的方案)
把原本的静态/动态子元素改成一个函数,让Wrapper内部根据条件决定要不要调用这个函数。这样只有当条件成立时,动态计算的代码才会执行,从根源避免报错。
首先改造你的SomeWrapper组件:
function SomeWrapper({ some: condition, children }) { if (!condition) { return null; // 条件不满足时直接返回null,不渲染任何内容 } // 如果需要用自定义元素包裹子元素,就换成: // return <YourCustomElement>{children()}</YourCustomElement> return children(); }
然后使用的时候,把动态内容放在函数里:
<SomeWrapper some={condition}> {() => ( <ul> {this.may.not.exist.unless.condition.map(item => <li>{item}</li>)} </ul> )} </SomeWrapper>
这样一来,只有当condition为true时,Wrapper才会调用这个函数,里面的.map()才会执行,完全不会触发undefined.map()的错误。
2. 在子元素内部提前做条件判断
如果不想修改Wrapper的结构,可以在子元素层面先检查condition,只有成立时才渲染动态内容:
<SomeWrapper some={condition}> {condition ? ( <ul> {this.may.not.exist.unless.condition.map(item => <li>{item}</li>)} </ul> ) : null} </SomeWrapper>
不过这种方式有点重复判断(Wrapper和子元素都检查了一次condition),如果Wrapper的逻辑复杂,后期维护容易出现不一致的问题,所以优先级不如第一种。
3. 使用renderProp替代子元素
和函数子元素逻辑类似,只是把函数放在单独的render属性里,写法上更明确:
改造Wrapper:
function SomeWrapper({ some: condition, render }) { if (!condition) return null; return render(); }
使用时:
<SomeWrapper some={condition} render={() => ( <ul> {this.may.not.exist.unless.condition.map(item => <li>{item}</li>)} </ul> )} />
这种方式和函数子元素效果完全一致,只是写法不同,看你个人习惯选择。
内容的提问来源于stack exchange,提问作者Tobia
相关产品推荐
相关产品推荐

