React HOC - Generic Container

时间:2018-04-10 23:54:16

标签: javascript reactjs redux functional-programming

向导和向导页

我正在尝试构建一个通用的Wizard和WizardPages,以便在我的应用程序中可以重复使用。我认为向导组件负责管理状态,而WizardPage将作为包装器工作,并将呈现Back,Cancel和Next按钮。它假设Next按钮(也许Back也是)应该发送一个redux动作。此操作可能会有所不同,具体取决于要包装的组件。这就是我的(不完整版):

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import withWizardLayout from '../../hoc/WithWizardLayout';

class Wizard extends Component {

  constructor(props) {
    super(props);
    this.state = {
      page: 0,
    };
  }
  nextPage = () => {
    this.setState({ page: this.state.page + 1 });
  };

  previousPage = () => {
    this.setState({ page: this.state.page - 1 });
  };

  render() {
    const { wizardPages } = this.props;
    const { page } = this.state;
    const wizardItem = wizardPages[page];
    const nextPage = this.nextPage;
    const previousPage = this.previousPage;
    const ComponentWrapped = withWizardLayout(wizardItem.ComponentWrapped, nextPage, previousPage);
    return (
      <ComponentWrapped />
    );
  }
}

 export default Wizard;


import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { compose } from 'react-apollo';
import { connect } from 'react-redux';
import { Flex, Box } from 'reflexbox';
import { BlueRoundButton, GreyRoundButton } from '../components/Button';

export default function withWizardLayout(ComponentDependent, nextPageCallBack, previousPageCallback) { 
  class WizardPage extends Component {
    previousPage = () => {
    };
    nextPage = () => {
      this.props.test();
    };   
    render() {
      const { ComponentWrapped, isFirstPage, isLastPage } = ComponentDependent;
        return (
          <Flex column>
            <ComponentWrapped
              isLastPage={isLastPage}
              isFirstPage={isFirstPage}
            >
              <Flex justify='flex-end'>
                <Flex mr='auto' w={0.1}>
                  <GreyRoundButton style={{ fontWeight: '500', position: 'relative', top: '10%' }}>Back</GreyRoundButton>
                </Flex>
                <Flex w={0.08} mr={2} align='center' justify='center' style={{ textAlign: 'center' }}>
                  <span>Cancel</span>
                </Flex>
                <Flex w={0.15} justify='center'>
                  <BlueRoundButton onClick={this.nextPage} style={{ position: 'relative', top: '10%', fontWeight: '500' }}>Continue</BlueRoundButton>
                </Flex>
              </Flex>
            </ComponentWrapped>
          </Flex>
        );
      }
  }

CustomersContainer

import { compose } from 'react-apollo';
import { connect } from 'react-redux';
import CustomerImport from '../components/Settings/CustomerImport';
import { withWizardLayout } from '../hoc/WithWizardLayout';
const mapStateToProps = null;

const mapDispatchToProps = dispatch => (
    {
        test: () => (dispatch(console.log("hi"))),
    }
);

export default compose(connect(null, mapDispatchToProps))(CustomerImport);

已连接的组件

import React, { Component } from 'react';
import styled from 'styled-components';
import {
  SettingBlock,
  NotifyBlock,
  SuccessMessage,
  ErrorMessage,
  Instructions,
} from './styles';

import ExcelUploader from '../ExcelUploader';

const ProgressBar = styled.div`
  width: 0;
  height: 30px;
  background-color: Green;
`;

const ExcelWrapper = styled.div`
  margin-bottom: 4rem;
`;

export default class CustomerImport extends Component {
  constructor(props) {
    super(props);

    this.state = {
      progress: 0,
      notify: {
        success: {
          message: '',
          active: false,
        },
        error: {
          message: '',
          active: false,
        },
      },
    };
  }


  render() {
    const { success, error } = this.state.notify;
    const ButtonsWrapper = this.props.children;
    return (
      <div>
        <NotifyBlock>
          <SuccessMessage className={success.active ? 'active' : null}>{success.message}</SuccessMessage>
          <ErrorMessage className={error.active ? 'active' : null}>{error.message}</ErrorMessage>
        </NotifyBlock>
        <SettingBlock>
          <h3>
            Import your customers
          </h3>
          <ProgressBar style={{ width: `${this.state.progress}%` }} />
          <Instructions>
            Select an Excel file containing your customer information.
            Need a template? <a href="">Grab one here.</a>
          </Instructions>
          <ExcelWrapper>
            <ExcelUploader />
          </ExcelWrapper>
          {ButtonsWrapper}
        </SettingBlock>
      </div>
    );
  }
}

这就是我应该如何呈现通用向导,我们可以拥有X向导页面:

const wizardPages = [
  {
    ComponentWrapped: CustomersContainer,
    isFirstPage: false,
    isLastPage: false,
  },
];

<Wizard wizardPages={wizardPages} />

这种方法的问题在于我想在withWizardLayout中使用按钮的onClick:

1)对父亲执行回调(可能,我作为道具处理者传递)

2)调用收到的容器调度操作。 (我无法访问已发送的操作,在本例中为this.props.test)

我如何重构这一点,想一个通用的方法来处理这个问题?我认为另一种重构方法(具有不同的withWizardLayout函数,但我在控制台上有渲染问题)。 也许我没有以最好的方式设计这个。 救命啊!

0 个答案:

没有答案