ฉันจะรวมองค์ประกอบการตอบสนองตามเงื่อนไขได้อย่างไร


90

ฉันมีส่วนประกอบที่บางครั้งจะต้องแสดงผล<anchor>เป็นไฟล์<div>. ผมอ่านเพื่อตรวจสอบนี้คือpropthis.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;
    }
}

คุณยังสามารถย้ายconst baseClasses =เข้าไปในif (this.props.link)สาขานั้นได้ ในขณะที่คุณใช้ ES6 ดังนั้นคุณยังสามารถทำให้ง่ายขึ้นเล็กน้อยโดยconst {link, className} = this.props;ใช้linkและclassNameเป็นตัวแปรท้องถิ่น
Sulthan

ผู้ชายฉันรักมัน เรียนรู้มากขึ้นเกี่ยวกับ ES6 และจะช่วยเพิ่มความสามารถในการอ่านเสมอ ขอบคุณสำหรับเคล็ดลับพิเศษ!
Brandon Durham

1
"การล็อกขั้นสุดท้าย" คืออะไร?
Chris Harrison

คำตอบ:


94

เพียงแค่ใช้ตัวแปร

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 เป็นรหัสเหมือนที่อื่น ๆ หากคุณต้องการลดความซ้ำซ้อนให้ใช้ฟังก์ชันและตัวแปร


23

สร้าง 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>
);

4
HOC น่าจะตายอย่างช้าๆ: P
Jamie Hutber

คำHOCนี้น่าเกลียด เป็นเพียงฟังก์ชันที่วางไว้ตรงกลาง ฉันเปลี่ยนชื่อ "HPC" ที่ดูทันสมัยอย่างกะทันหัน สิ่งที่มีลำดับสูงมากเกี่ยวกับฟังก์ชั่นง่ายๆที่วางอยู่ระหว่าง ...
vsync

13

นี่คือตัวอย่างของส่วนประกอบที่เป็นประโยชน์ที่ฉันเคยเห็น (ไม่แน่ใจว่าจะให้ใครรับรอง) ที่ทำงานได้:

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

ใช้กรณี:

<ConditionalWrap condition={someCondition}
  wrap={children => (<a>{children}</a>)} // Can be anything
>
  This text is passed as the children arg to the wrap prop
</ConditionalWrap>

2
เครดิตควรไปที่นี่: gist.github.com/kitze/23d82bb9eb0baabfd03a6a720b1d637f
Roy Prins

ฉันเห็นสิ่งนั้นจาก kitze แต่ฉันไม่แน่ใจว่าเขาได้แนวคิดมาจากคนอื่น
antony

ไม่ใช่ฉันนี่เป็นผลลัพธ์แรกที่โผล่ขึ้นมาและฉันคิดว่ามันเป็นแหล่งที่มา - หรืออย่างน้อยก็ใกล้เคียงที่สุด;)
Roy Prins

คุณควรใช้wrapคำสั่งอย่างเปิดเผยและไม่ใช่เป็นฟังก์ชันเพื่อให้สิ่งต่างๆมากขึ้น "React" -spirit
vsync

คุณจะทำให้ @vsync เปิดเผยมากขึ้นได้อย่างไร? ฉันคิดว่าอุปกรณ์การแสดงผลอยู่ในจิตวิญญาณของ React?
antony

10

มีอีกวิธีหนึ่งที่คุณสามารถใช้ตัวแปรอ้างอิงได้

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>

)

คุณสามารถย่อครึ่งแรกถึงlet Wrapper = someCondition ? ParentComponent : React.Fragment
mpoisot

นี่เป็นสิ่งที่ยอดเยี่ยม แต่บางครั้งคุณต้องการให้รหัสประกาศไว้ซึ่งหมายความว่าจะส่งคืนเฉพาะ JSX
vsync

ฉันได้รับข้อผิดพลาด React.Fragment can only have 'key' and 'children'เนื่องจากฉันส่งอุปกรณ์ประกอบฉากบางอย่างไปยัง "</ pper >" เช่น"className"เป็นต้น
vsync

@vsync คุณต้องเพิ่มเงื่อนไขสำหรับอุปกรณ์ประกอบฉากด้วยเช่น propId = {someCondition? parentProps: undefined} ..
Avinash

1
ฉันรู้ :) ฉันเขียนสิ่งนี้เพื่อประโยชน์ในการจัดทำเอกสารสำหรับผู้อื่นที่มาพร้อมกับปัญหานี้ดังนั้น Google จะแคชหน้านี้ในผลการค้นหาสำหรับคำหลักเหล่านั้น
vsync

1

คุณยังสามารถใช้ฟังก์ชัน util เช่นนี้:

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

1
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


0

คุณควรใช้ JSX ถ้า-อื่นตามที่อธิบายไว้ที่นี่ สิ่งนี้ควรใช้งานได้

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

-2

ส่วนประกอบที่ใช้งานได้ซึ่งแสดงผล 2 องค์ประกอบหนึ่งถูกห่อหุ้มและอีกชิ้นไม่ได้

วิธีที่ 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>

สิ่งนี้สามารถใช้ได้เช่นนี้:

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

วิธีที่ 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>

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.