简体   繁体   English

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

[英]How do I conditionally wrap a React component?

I have a component that will sometimes need to be rendered as an <anchor> and other times as a <div> .我有一个组件,有时需要呈现为<anchor> ,有时需要呈现为<div> The prop I read to determine this, is this.props.url .我为确定这一点而阅读的propthis.props.url

If it exists, I need to render the component wrapped in an <a href={this.props.url}> .如果存在,我需要渲染包装在<a href={this.props.url}>中的组件。 Otherwise it just gets rendered as a <div/> .否则它只会被渲染为<div/>

Possible?可能的?

This is what I'm doing right now, but feel it could be simplified:这就是我现在正在做的事情,但觉得它可以简化:

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

UPDATE:更新:

Here is the final lockup.这是最后的锁定。 Thanks for the tip, @Sulthan !感谢您的提示, @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;
    }
}

Just use a variable.只需使用一个变量。

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;

or, you can use a helper function to render the contents.或者,您可以使用辅助函数来呈现内容。 JSX is code like any other. JSX 和其他代码一样。 If you want to reduce duplications, use functions and variables.如果要减少重复,请使用函数和变量。

Create a HOC (higher-order component) for wrapping your element:创建一个 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>
);

Here's an example of a helpful component I've seen used before (not sure who to accredit it to) which might be more declarative:这是我以前见过的一个有用组件的示例(不确定该授权给谁),它可能更具声明性:

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

Use case:用例:

// This children of this MaybeInAModal component will appear as-is or within a modal
// depending on whether "shouldOpenInModal" is truthy
const MaybeInAModal = ({ children, shouldOpenInModal }) => {
  return (
    <ConditionalWrap
      condition={shouldOpenInModal}
      wrap={wrappedChildren => (<Modal>{wrappedChildren}</Modal>)}
        {children}
    </ConditionalWrap>
  );
}

There's another way you could use a reference variable还有另一种方法可以使用引用变量

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>

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

The component you wanna wrap as您要包装的组件

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

Maybe this article can help you more https://blog.hackages.io/conditionally-wrap-an-element-in-react-a8b9a47fab2也许这篇文章可以帮助你更多https://blog.hackages.io/conditionally-wrap-an-element-in-react-a8b9a47fab2

You could also use this component: conditional-wrap 您也可以使用此组件: conditional-wrap

A simple React component for wrapping children based on a condition. 一个简单的React组件,用于根据条件包装子项。

You should use a JSX if-else as described here .您应该使用此处描述的 JSX if-else。 Something like this should work.像这样的东西应该工作。

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

You could also use a util function like this:您还可以使用这样的 util 函数:

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

Using react and Typescript使用反应和打字稿

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

A functional component which renders 2 components, one is wrapped and the other isn't.一个功能组件,它呈现 2 个组件,一个被包装,另一个没有。

Method 1:方法一:

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

This can also be used like this:这也可以像这样使用:

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

Method 2:方法二:

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

With provided solutions there is a problem with performance: https://medium.com/@cowi4030/optimizing-conditional-rendering-in-react-3fee6b197a20提供的解决方案存在性能问题: https ://medium.com/@cowi4030/optimizing-conditional-rendering-in-react-3fee6b197a20

React will unmount <Icon> component on the next render. React 将在下一次渲染时卸载<Icon>组件。 Icon exist twice in different order in JSX and React will unmount it if you change props.link on next render. Icon在 JSX 中以不同的顺序存在两次,如果您在下次渲染时更改props.link ,React 将卸载它。 In this case <Icon> its not a heavy component and its acceptable but if you are looking for an other solutions:在这种情况下, <Icon>它不是一个沉重的组件并且可以接受,但是如果您正在寻找其他解决方案:

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我如何有条件地加载我的React组件? - How do i load my React component conditionally? 如何包装React组件? - How can I wrap React component? 如何在 React 中的对象数组上 map,然后根据先前的值有条件地渲染组件? - How do I map over an array of objects in React and then conditionally render a component based on a previous value? 我从一个父组件渲染 5 列,它们都有不同的图标。 我如何有条件地让他们做出反应? - I'm rendering 5 columns from a single parent component and they all have different icons. How do i conditionally render them in react? 如何根据特定页面有条件地呈现 Gatsby 中的组件? - How do I conditionally render a component in Gatsby based on specific page? 如何根据 prop 有条件地渲染组件的颜色? - How do I conditionally render the color of my component based on the prop? 有条件地将按钮与另一个组件包装在一起 - Conditionally Wrap Button with Another Component 如何包装返回多个表行的 React 组件并避免“<tr> 不能作为孩子出现<div> ”错误? - How do I wrap a React component that returns multiple table rows and avoid the “<tr> cannot appear as a child of <div>” error? 我如何有条件地在反应中呈现字体真棒图标 - How do I conditionally render font awesome icons in react 如何有条件地禁用 React JS 中表单选择中的选项? - How do I conditionally disable an option in a form select in React JS?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM