如何有条件地包装 React 组件?

我有一个组件,有时需要作为一个 <anchor>和其他时候作为一个 <div>呈现。我读取的 prop来确定这个,是 this.props.url

如果它存在,我需要呈现包装在 <a href={this.props.url}>中的组件。否则它只会被呈现为 <div/>

可能吗?

这就是我现在正在做的事情,但我觉得可以简化一下:

if (this.props.link) {
return (
<a href={this.props.link}>
<i>
{this.props.count}
</i>
</a>
);
}


return (
<i className={styles.Icon}>
{this.props.count}
</i>
);

更新:

这里是最后的锁定。谢谢你的提示,@ Sulthan

import React, { Component, PropTypes } from 'react';
import classNames from 'classnames';


export default class CommentCount extends Component {


static propTypes = {
count: PropTypes.number.isRequired,
link: PropTypes.string,
className: PropTypes.string
}


render() {
const styles = require('./CommentCount.css');
const {link, className, count} = this.props;


const iconClasses = classNames({
[styles.Icon]: true,
[className]: !link && className
});


const Icon = (
<i className={iconClasses}>
{count}
</i>
);


if (link) {
const baseClasses = classNames({
[styles.Base]: true,
[className]: className
});


return (
<a href={link} className={baseClasses}>
{Icon}
</a>
);
}


return Icon;
}
}
59899 次浏览

只要用一个变量。

var component = (
<i className={styles.Icon}>
{this.props.count}
</i>
);


if (this.props.link) {
return (
<a href={this.props.link} className={baseClasses}>
{component}
</a>
);
}


return component;

或者,您可以使用助手函数来呈现内容。JSX 和其他代码一样是代码。如果要减少重复,可以使用函数和变量。

您应该使用描述为 给你的 JSX if-else。

App = React.creatClass({
render() {
var myComponent;
if(typeof(this.props.url) != 'undefined') {
myComponent = <myLink url=this.props.url>;
}
else {
myComponent = <myDiv>;
}
return (
<div>
{myComponent}
</div>
)
}
});

创建一个 HOC (高阶组件)来包装元素:

const WithLink = ({ link, className, children }) => (link ?
<a href={link} className={className}>
{children}
</a>
: children
);


return (
<WithLink link={this.props.link} className={baseClasses}>
<i className={styles.Icon}>
{this.props.count}
</i>
</WithLink>
);

您也可以使用如下的 util 函数:

const wrapIf = (conditions, content, wrapper) => conditions
? React.cloneElement(wrapper, {}, content)
: content;

下面是我以前见过的一个有用的组件示例(不确定应该授权给谁)。可以说,这句话更具有说服力:

const ConditionalWrap = ({ condition, wrap, children }) => (
condition ? wrap(children) : children
);

用例:

// MaybeModal will render its children within a modal (or not)
// depending on whether "isModal" is truthy
const MaybeModal = ({ children, isModal }) => {
return (
<ConditionalWrap
condition={isModal}
wrap={(wrappedChildren) => <Modal>{wrappedChildren}</Modal>}
>
{children}
</ConditionalWrap>
);
}

还有别的办法 你可以使用一个引用变量

let Wrapper = React.Fragment //fallback in case you dont want to wrap your components


if(someCondition) {
Wrapper = ParentComponent
}


return (
<Wrapper parentProps={parentProps}>
<Child></Child>
</Wrapper>


)

一个呈现两个组件的功能组件,一个是封装的,另一个不是。

方法一:

// The interesting part:
const WrapIf = ({ condition, With, children, ...rest }) =>
condition
? <With {...rest}>{children}</With>
: children


 

    

const Wrapper = ({children, ...rest}) => <h1 {...rest}>{children}</h1>




// demo app: with & without a wrapper
const App = () => [
<WrapIf condition={true} With={Wrapper} style=\{\{color:"red"}}>
foo
</WrapIf>
,
<WrapIf condition={false} With={Wrapper}>
bar
</WrapIf>
]


ReactDOM.render(<App/>, document.body)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

这也可以这样使用:

<WrapIf condition={true} With={"h1"}>

方法二:

// The interesting part:
const Wrapper = ({ condition, children, ...props }) => condition
? <h1 {...props}>{children}</h1>
: <React.Fragment>{children}</React.Fragment>;
// stackoverflow prevents using <></>
  



// demo app: with & without a wrapper
const App = () => [
<Wrapper condition={true} style=\{\{color:"red"}}>
foo
</Wrapper>
,
<Wrapper condition={false}>
bar
</Wrapper>
]


ReactDOM.render(<App/>, document.body)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

const ConditionalWrapper = ({ condition, wrapper, children }) =>
condition ? wrapper(children) : children;

要包装为的组件

<ConditionalWrapper
condition={link}
wrapper={children => <a href={link}>{children}</a>}>
<h2>{brand}</h2>
</ConditionalWrapper>

也许这篇文章能帮到你更多 Https://blog.hackages.io/conditionally-wrap-an-element-in-react-a8b9a47fab2

提供的解决方案存在性能问题: Https://medium.com/@cowi4030/optimizing-conditional-rendering-in-react-3fee6b197a20

React 将在下次渲染时卸载 <Icon>组件。 Icon在 JSX 中以不同的顺序存在两次,如果您在下次呈现时更改 props.link,React 将卸载它。在这种情况下,<Icon>不是一个沉重的组成部分,它是可以接受的,但如果你正在寻找其他解决方案:

Https://codesandbox.io/s/82jo98o708?file=/src/index.js

Https://thoughtspile.github.io/2018/12/02/react-keep-mounted/

使用反应和打字稿

let Wrapper = ({ children }: { children: ReactNode }) => <>{children} </>


if (this.props.link) {
Wrapper = ({ children }: { children: ReactNode }) => <Link to={this.props.link}>{children} </Link>
}


return (
<Wrapper>
<i>
{this.props.count}
</i>
</Wrapper>
)