0

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

为了在同一页面上,这里是我目前使用 if-else 语句呈现的不同着陆组件。

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);
4

3 回答 3

0

我会在这里选择组合而不是继承,这意味着创建许多可重用的组件并将您的顶级组件与那些可重用的组件组合在一起,而不是让您的顶级组件继承自一种常见的组件类型。如果您采用后一种方法,您最终可能会得到一份我认为比您现在拥有的更好的道具清单。

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

页眉.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>
  );
}
于 2018-06-14T15:12:28.810 回答
0

在这种特殊情况下,我不认为 hoc 是矫枉过正的。我认为,只要您可以使用 hoc 以获得更好的可读性和可用性,就使用它。

使用一些recompose hocs (你应该安装 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]))
  )
)

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

[ condition, left(如果条件为真), right(else)]

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

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

当 right 为空时 - 如果条件不成立,它将渲染我们包装的组件

然后你可以使用 hoc:

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

我建议开始使用 recompose hocs,它们很棒!

于 2018-06-25T07:17:42.613 回答
0

一个“技巧”可能是在根 div 上附加一个 className 用于景观,即 'student' 'professor' 或 'logout' 并使用 css display: none 在每个场景中隐藏不需要的项目

另一种方法是保留您的 3 个组件,但将所有渲染委托给一个通用的“LandingRenderer”组件,该组件将接受诸如“showJoinClassButton”“showCreateButtonButton”等布尔属性。

然后你的 3 个组件渲染看起来像这样

LandingProfessor: (props) => (
    <LandingRenderer 
        showJoinClassButton={false} 
        showCreateClassButton={true} 
        ... 
        {...props} />
)
于 2018-06-14T15:02:06.487 回答