Tenho um componente que às vezes precisa ser renderizado como um <anchor>
e outras vezes como um <div>
. O prop
que li para determinar isso, é this.props.url
.
Se existir, preciso renderizar o componente envolvido em um <a href={this.props.url}>
. Caso contrário, ele apenas será renderizado como um <div/>
.
Possível?
Isso é o que estou fazendo agora, mas sinto que poderia ser simplificado:
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>
);
ATUALIZAR:
Aqui está o travamento final. Obrigado pela dica, @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;
}
}
javascript
reactjs
Brandon Durham
fonte
fonte
const baseClasses =
para esseif (this.props.link)
galho. Como você está usando o ES6, também pode simplificar um poucoconst {link, className} = this.props;
usandolink
eclassName
como variáveis locais.Respostas:
Basta usar uma variável.
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;
ou você pode usar uma função auxiliar para renderizar o conteúdo. JSX é um código como qualquer outro. Se você quiser reduzir as duplicações, use funções e variáveis.
fonte
Crie um HOC (componente de ordem superior) para envolver seu elemento:
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> );
fonte
HOC
é horrível. É apenas uma função colocada no meio. Eu realmente desloco esse nome repentinamente na moda "HPC". o que é tão importante em uma função simples que é colocada entre ... conceito antigo por décadas.Aqui está um exemplo de um componente útil que vi ser usado (não tenho certeza para quem creditar) que faz o trabalho:
const ConditionalWrap = ({ condition, wrap, children }) => ( condition ? wrap(children) : children );
Caso de uso:
<ConditionalWrap condition={someCondition} wrap={children => (<a>{children}</a>)} // Can be anything > This text is passed as the children arg to the wrap prop </ConditionalWrap>
fonte
wrap
declarativamente e não como uma função para manter as coisas mais "React" -spiritHá outra maneira de usar uma variável de referência
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> )
fonte
let Wrapper = someCondition ? ParentComponent : React.Fragment
React.Fragment can only have 'key' and 'children'
porque passo alguns adereços para "<Wrapper>" como "className" e entãoVocê também pode usar uma função util como esta:
const wrapIf = (conditions, content, wrapper) => conditions ? React.cloneElement(wrapper, {}, content) : content;
fonte
const ConditionalWrapper = ({ condition, wrapper, children }) => condition ? wrapper(children) : children;
O componente que você quer envolver como
<ConditionalWrapper condition={link} wrapper={children => <a href={link}>{children}</a>}> <h2>{brand}</h2> </ConditionalWrapper>
Talvez este artigo possa ajudá-lo mais https://blog.hackages.io/conditionally-wrap-an-element-in-react-a8b9a47fab2
fonte
Você deve usar um JSX if-else conforme descrito aqui . Algo assim deve funcionar.
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> ) } });
fonte
Um componente funcional que renderiza 2 componentes, um é empacotado e o outro não.
Método 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>
Isso também pode ser usado assim:
<WrapIf condition={true} With={"h1"}>
Método 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>
fonte