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

问题描述 投票:0回答:11

我有一个组件,有时需要渲染为

<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>
);
javascript reactjs
11个回答
145
投票

只需使用变量即可。

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 是与其他代码一样的代码。如果你想减少重复,请使用函数和变量。


51
投票

创建一个 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>
);

46
投票

这是我以前见过的有用组件的示例(不确定该将其授权给谁)。可以说它更具声明性:

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>
  );
}

26
投票

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

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>

)

8
投票
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


1
投票

您还可以使用这样的 util 函数:

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

0
投票

您应该使用 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>
        )
    }
});

0
投票

一个功能组件,它呈现 2 个组件,一个被包装,另一个没有。

方法一:

// 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>


0
投票

使用反应和打字稿

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>
)


0
投票

我个人正在使用这种代码(ComponentChildren是Preact,你应该能够使用ReactNode进行React):

const Parent = ({ children }: { children: ComponentChildren }) => props.link != null ?
        <a href={ props.link }>{ children }</a> :
        <>{ children }</>

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

-1
投票

提供的解决方案存在性能问题: 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/

© www.soinside.com 2019 - 2024. All rights reserved.