比React Component更喜欢纯函数?

时间:2016-03-14 13:51:54

标签: javascript reactjs redux pure-function

我正在为一家法国公司制作HTMl5视频播放器。我们使用React和Redux来构建UI,它运行良好,编码非常愉快!我们目前使用eslint-plugin-react来检查React代码样式。从上一个版本开始,linter建议使用纯函数而不是React Components(view the rule),但它在我的团队中引发了一些争论。

我们已经将纯函数用于非常小的组件,这些组件总是呈现相同的东西(对于给定的道具)。没问题。但对于更大的组件,在我看来,纯函数似乎使代码不那么优雅(并且与其他组件相比不那么均匀)。

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

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 Component的结构。由于ES7,PropTypes和默认道具可以在课堂内,纯函数无法实现。而且,在这个例子中,我们有很多功能来渲染子组件。

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

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

非常感谢你的帮助!

0 个答案:

没有答案