Рефакторинг и очистка кода в действии - работа с условиями и компонентами оболочки - PullRequest
0 голосов
/ 29 февраля 2020

Есть ли более чистый способ выполнить условие в реактивном компоненте? Скажем, у меня есть что-то вроде этого:

<Track>
  <ProductLink>
    <Image ... /> 
    <Typography ...>{...}</Typography>
    <Typography ...>{...}</Typography>
  </ProductLink>
</Track>

И с условиями это будет выглядеть так:

{condition ? <Track><ProductLink> : <> }
  <Image ... /> 
  <Typography ...>{...}</Typography>
  <Typography ...>{...}</Typography>
{condition ? </ProductLink></Track> : </> }

Есть ли другой способ выполнить условие? Если условие выполнено, используйте компонент Track и ProductLink, если нет, просто отобразите компонент Fragment.

1 Ответ

0 голосов
/ 29 февраля 2020

Я бы порекомендовал поднять Track и ProductLink в повторно используемый компонент - таким образом вы упростите его до одного условия.

Например:

import React from "react";
import PropTypes from "prop-types";
import Track from "./path/to/Track";
import ProductLink from "./path/to/ProductLink";   

const TrackProduct = ({ children, isTracked }) => (
 isTracked 
  ? <Track>
      <ProductLink>
       {children}
      </ProductLink>
    </Track>
  : children
);

TrackProduct.proptTypes = {
  children: PropTypes.node.isRequired,
  isTracked: PropTypes.bool.isRequired
};

export default TrackProduct;

Затем импортируйте вышеуказанный повторно используемый компонент и управляйте им с помощью state:

import React from "react";
import TrackProduct from "./path/to/TrackProduct";
import Image from "./path/to/Image";
import Typography from "./path/to/Typography";
import Button from "./path/to/Button";

class Example extends Component {
  state = { isTracked: false };

  toggleTrack = () => this.setState(prevState => ({ track: !prevState.isTracked }))

  render = () => (
    <TrackProduct isTracked={this.state.isTracked}>
      <Image ... /> 
      <Typography ...>{...}</Typography>
      <Typography ...>{...}</Typography>
      <Button onClick={this.toggleTrack}>
        {!this.state.isTracked ? "Track" : "Untrack"} Product
      </Button>
    </TrackProduct>
  )
};

export default Example;

Если вышеприведенное не совсем работает и / или слишком повторяется, то вы можете использовать реквизит рендеринга, который передает некоторые из своих собственных полей состояния и класса в управляемую дочернюю функцию (я предпочитаю этот метод, а не HOC-оболочки, поскольку их легче проверять).

Например:

import React, { Component } from "react";
import PropTypes from "prop-types";
import Track from "./path/to/Track";
import ProductLink from "./path/to/ProductLink";   

class TrackProduct extends Component {
  state = { isTracked: false };

  toggleTrack = () => this.setState(prevState => ({ track: !prevState.isTracked }))

  render = () => {
    const renderedChildren = this.props.children({ 
      isTracked: this.state.isTracked,   
      toggleTrack: this.toggleTrack
    });

    return (
      isTracked 
        ? <Track>
            <ProductLink>
              {renderedChildren}
            </ProductLink>
          </Track>
        : renderedChildren
    )
  };
};

TrackProduct.proptTypes = {
  children: PropTypes.func.isRequired,
};

export default TrackProduct;

Затем импортируйте вышеупомянутый многократно используемый компонент рендеринга и управляйте им с помощью пропущенных реквизитов TrackProduct (isTracked и toggleTrack):

import React from "react";
import TrackProduct from "./path/to/TrackProduct";
import Image from "./path/to/Image";
import Typography from "./path/to/Typography";
import Button from "./path/to/Button";

const Example = () => (
  <TrackProduct>
    {({ isTracked, toggleTrack }) => (
      <>
        <Image ... /> 
        <Typography ...>{...}</Typography>
        <Typography ...>{...}</Typography>
        <Button onClick={toggleTrack}>
          {!isTracked ? "Track" : "Untrack"} Product
        </Button>
      </>
    )}
  </TrackProduct>
);

export default Example;

Более подробную информацию о реквизитах рендеринга можно найти в этом Феникс ReactJS конференц-разговор .

...