2

我正在为一家法国公司开发 HTMl5 视频播放器。我们使用 React 和 Redux 来构建 UI,效果非常好,编写代码非常愉快!我们目前使用eslint-plugin-react来检查 React 代码风格。自上一个版本以来,linter 建议使用纯函数而不是 React 组件(查看规则),但这在我的团队中引发了一些争论。

我们已经将纯函数用于渲染总是相同的东西的非常小的组件(对于给定的道具)。没有问题。但是对于更大的组件,在我看来,纯函数似乎使代码不那么优雅(与其他组件相比也不那么统一)。

这是我们应该更改的组件之一的示例:

const ControlBar = ({ actions, core, root }) => {
  const onFullscreenScreen = (isFullscreen) => {
    const playerRoot = root;
    if (isFullscreen && !screenfull.isFullscreen) {
      screenfull.request(playerRoot);
    } else {
      screenfull.exit();
    }
  };
​
  const renderIconButton = (glyph, action, label = false) => {
    let content = (
      <Button modifier="icon" clickCallback={ action }>
        <Icon glyph={ glyph } />
      </Button>
    );
    if (label) {
      content = <TooltipOrigin content={label}>{content}</TooltipOrigin>;
    }
    return content;
  };
​
  const renderPlayButton = () => {
    const { play, pause } = actions;
    const { playerState } = core;
    if (playerState === CoreStates.PAUSED) {
      return renderIconButton(playGlyph, play, 'lecture');
    }
    return renderIconButton(pauseGlyph, pause, 'pause');
  };
​
  const renderMuteButton = () => {
    const { mute, unmute } = actions;
    const { currentVolume } = core;
    if (currentVolume === 0) {
      return renderIconButton(muteGlyph, unmute);
    }
    return renderIconButton(volumeGlyph, mute);
  };
​
  const renderFullscreenButton = () => {
    const { isFullscreen } = core;
    if (!isFullscreen) {
      return renderIconButton(fullscreenGlyph, () => { onFullscreenScreen(true); });
    }
    return renderIconButton(fullscreenExitGlyph, () => { onFullscreenScreen(false); });
  };
​
  const { setCurrentVolume } = actions;
  const { currentVolume } = core;
  return (
    <div className={ style.ControlBar }>
      <div className={ style.audio }>
        { renderMuteButton() }
        <SoundBar setCurrentVolume={ setCurrentVolume } volume={ currentVolume } />
      </div>
      <div className={ style.controls }>
        { renderPlayButton() }
      </div>
      <div className={ style.settings }>
        { renderFullscreenButton() }
      </div>
    </div>
  );
};
​
ControlBar.propTypes = {
  actions: PropTypes.object.isRequired,
  core: PropTypes.object.isRequired,
  root: PropTypes.object.isRequired,
};
​
export default ControlBar;

相对 :

export default class ControlBar extends Component {

  static propTypes = {
    actions: PropTypes.object.isRequired,
    core: PropTypes.object.isRequired,
    root: PropTypes.object.isRequired,
  };

  onFullscreenScreen(isFullscreen) {
    const playerRoot = this.props.root;

    if (isFullscreen && !screenfull.isFullscreen) {
      screenfull.request(playerRoot);
    } else {
      screenfull.exit();
    }
  }

  renderIconButton(glyph, action, label = false) {
    let content = (
      <Button modifier="icon" clickCallback={ action }>
        <Icon glyph={ glyph } />
      </Button>
    );
    if (label) {
      content = <TooltipOrigin content={label}>{content}</TooltipOrigin>;
    }
    return content;
  }

  renderPlayButton() {
    const { play, pause } = this.props.actions;
    const { playerState } = this.props.core;
    if (playerState === CoreStates.PAUSED) {
      return this.renderIconButton(playGlyph, play, 'lecture');
    }
    return this.renderIconButton(pauseGlyph, pause, 'pause');
  }

  renderMuteButton() {
    const { mute, unmute } = this.props.actions;
    const { currentVolume } = this.props.core;
    if (currentVolume === 0) {
      return this.renderIconButton(muteGlyph, unmute);
    }
    return this.renderIconButton(volumeGlyph, mute);
  }

  renderFullscreenButton() {
    const { isFullscreen } = this.props.core;
    if (!isFullscreen) {
      return this.renderIconButton(fullscreenGlyph, () => { this.onFullscreenScreen(true); });
    }
    return this.renderIconButton(fullscreenExitGlyph, () => { this.onFullscreenScreen(false); });
  }

  render() {
    const { setCurrentVolume } = this.props.actions;
    const { currentVolume } = this.props.core;
    return (
      <div className={ style.ControlBar }>
        <div className={ style.audio }>
          { this.renderMuteButton() }
          <SoundBar setCurrentVolume={ setCurrentVolume } volume={ currentVolume } />
        </div>
        <div className={ style.controls }>
          { this.renderPlayButton() }
        </div>
        <div className={ style.settings }>
          { this.renderFullscreenButton() }
        </div>
      </div>
    );
  }

}

我们喜欢 React 组件的结构。由于 ES7,PropTypes 和默认 props 可以在类中,这在纯函数中是不可能的。而且,特别是在这个例子中,我们有很多函数来渲染子组件。

如果我们不喜欢,我们可以简单地禁用此规则,但我们真的很想了解这一点,并且我们关心性能和 React 的良好实践。所以,也许你可以帮助我们。

你怎么能帮助我?关于这个有趣的问题,我会得到其他意见。支持纯函数的论据是什么?也许解决方案不是在纯函数中更改 ControlBar 组件,而只是对其进行改进。在这种情况下,您对此有何建议?

非常感谢你的帮助 !

4

0 回答 0