在非常相似的组件的情况下,条件渲染的最佳方法是什么?

时间:2018-06-14 14:00:06

标签: javascript reactjs jsx higher-order-components conditional-rendering

我根据用户是教授,学生还是未登录来呈现不同的目标网页。目标网页非常相似;唯一的区别是显示的按钮。我知道我可以使用内联条件或简单的if-else语句来解决这个问题。但是,我想知道最佳实践在这种情况下实现条件呈现是什么。我知道更高阶的组件(HOC)可以提供帮助,但我不确定它们在这种特殊情况下是否过度。

要在同一页面上,以下是我目前使用if-else语句呈现的不同Landing组件。

Landing.js(未登记的用户):

import React from 'react';
import { withRouter } from 'react-router-dom';
import { compose } from 'recompose';
import { withEither } from '../../helpers/withEither';
import LandingStudent from './LandingStudent';
import LandingProfessor from './LandingProfessor';
import './Landing.css';

const Landing = ({ history }) => {
  return(
    <div className="header">
      <div className="text-box">
        <h1 className="header-primary">
          <span className="header-primary-main">
            QME
          </span>
          <span className="header-primary-sub">
            the best way to ask questions
          </span>
        </h1>
      </div>
    </div>
  );
};

export default Landing;

LandingProfessor.js

import React from 'react';
import { withRouter } from 'react-router-dom';
import RaisedButton from 'material-ui/RaisedButton';
import './Landing.css';

const LandingProfessor = ({ history }) => {
  return(
    <div className="header">
      <div className="text-box">
        <h1 className="header-primary">
          <span className="header-primary-main">
            QME
          </span>
          <span className="header-primary-sub">
            the best way to ask questions
          </span>
        </h1>
        <RaisedButton
          className="btn-animated btn-landing"
          label="Create Class"
          onClick={() => history.push('/courses/new')}
        />
        <RaisedButton
          className="btn-animated btn-landing"
          label="Dashboard"
          onClick={() => history.push('/courses')}
        />
      </div>
    </div>
  );
};

export default withRouter(LandingProfessor);

LandingStudent.js

import React from 'react';
import { withRouter } from 'react-router-dom';
import RaisedButton from 'material-ui/RaisedButton';
import './Landing.css';

const Landing = ({ history }) => {
  return(
    <div className="header">
      <div className="text-box">
        <h1 className="header-primary">
          <span className="header-primary-main">
            QME
          </span>
          <span className="header-primary-sub">
            the best way to ask questions
          </span>
        </h1>
        <RaisedButton
          className="btn-animated btn"
          label="Join Class"
          onClick={() => history.push('/courses/join')}
        />
      </div>
    </div>
  );
};

export default withRouter(Landing);

3 个答案:

答案 0 :(得分:0)

A&#39;技巧&#39;可以在景观的根div上附加一个className,即&#39; student&#39; &#39;教授&#39;或者&#39;退出&#39;并使用css display:none来隐藏每个场景中不需要的项目

另一种方法是保留3个组件,但将所有渲染委托给一个普通的LandingRenderer&#39;可以接受布尔属性的组件,例如&#39; showJoinClassButton&#39; &#39; showCreateButtonButton&#39;等

然后你的3个组件呈现就像这样的内容

LandingProfessor: (props) => (
    <LandingRenderer 
        showJoinClassButton={false} 
        showCreateClassButton={true} 
        ... 
        {...props} />
)

答案 1 :(得分:0)

我会在这里选择合成而不是继承,这意味着创建许多可重用的组件,并使用那些可重用的组件构建顶级组件,而不是让您的顶级组件从一个公共组件类型继承。如果你采用后一种方法,你可能会得到一个我认为比现在更好的道具清单。

首先,您可以对标题进行组件化:

Header.js

export default function Header(props) {
  return (
    <h1 className="header-primary">
      {props.children}
    </h1>
  );
}

Header.Main = function HeaderMain(props) {
  return (
    <span className="header-primary-main">
      {props.children}
    </span>
  );
};

Header.Sub = function HeaderSub(props) {
  return (
    <span className="header-primary-sub">
      {props.children}
    </span>
  );
};

并在Landing.js中使用它:

import Header from './Header.js';

const Landing = ({ history }) => {
  return(
    <div className="header">
      <div className="text-box">
        <Header>
          <Header.Main>QME</Header.Main>
          <Header.Sub>the best way to ask questions</Header.Sub>
        </Header>
      </div>
    </div>
  );
}

答案 2 :(得分:0)

在这种特殊情况下,我认为临时性的做法并不过分。 我认为只要可以使用hoc来提高可读性和可用性,就可以使用它。

使用recompose个临时文件夹(您应该安装重新组合:npm install recompose

export const renderByConditions = (...conditions) => compose(
  ...conditions.map(condition =>
    branch(condition[0], (condition[1] && renderComponent(condition[1])) || renderNothing, condition[2] && renderComponent(condition[2]))
  )
)

您应该传递带有签名的数组:

[{conditionleft(如果条件为真),right(其他)]

condition - (ownProps) => youCondition
left - Component | empty
right - Component | empty

当left为空时-如果条件为true,它将呈现null。

当right为空时-如果条件不为真,它将呈现我们包装的组件

然后您可以使用临时选项:

renderByConditions(
  [props => props.landing, props => <Landing {...props}/>],
  [props => props.proffesor, LandingProfessor],
  [props => props.student, LandingStudent],
  [Component => Component, DefaultComponent]
)

我建议您开始使用重组hoc,它们很棒!