我如何将状态从这个孩子传递给父组件?

问题描述 投票:0回答:1

我有2个组件OptinPage(父级)和TermsOfServices(子级)。 Optin Page仅用于呈现“ TermsOfServices”组件,该组件可在应用程序的其他位置重用。我想在OptinPage组件中使用我的TermsOfServices组件的状态来显示条件页面数(1 / 2、2 / 2)。没有Redux怎么办?

我的服务条款组件:

import API from 'api';
    import React, { PureComponent } from 'react';
    import PropTypes from 'prop-types';
    import {
      Block,
      BlockTitle,
      Col,
      Fab,
      Icon,
      Preloader,
    } from 'framework7-react';
    import { FormattedMessage } from 'react-intl';
    import { connect } from 'react-refetch';
    import ReactHtmlParser from 'react-html-parser';

    class TermsOfServices extends PureComponent {
      static propTypes = {
        agreeTosFunc: PropTypes.func.isRequired,
        agreeTos: PropTypes.object,
        onSucceeded: PropTypes.func,
        tos: PropTypes.object.isRequired,
      };

      static contextTypes = {
        apiURL: PropTypes.string,
        loginToken: PropTypes.string,
        userId: PropTypes.string,
      };

      static defaultProps = {
        agreeTos: {},
        onSucceeded: () => {},
      };

      state = {
        currentTos: -1,
      };

      componentDidUpdate(prevProps) {
        const {
          agreeTos,
          onSucceeded,
          tos,
        } = this.props;
        const { currentTos } = this.state;

        /* Prepare for first tos after receiving all of them */
        if (
          prevProps.tos.pending &&
          tos.fulfilled &&
          tos.value.length &&
          currentTos < 0
        ) {
          this.setState({ currentTos: 0 });
        }

        /* When sending ToS agreement is done */
        if (
          prevProps.agreeTos.pending &&
          agreeTos.fulfilled
        ) {
          onSucceeded();
        }
      }

      handleNext = () => {
        const { agreeTosFunc, tos } = this.props;
        const { currentTos: currentTosId } = this.state;
        const termsOfServices = tos.value;
        const done = currentTosId + 1 === termsOfServices.length;
        this.setState({ currentTos: currentTosId + 1 });
        if (done) {
          agreeTosFunc(termsOfServices.map((v) => v._id));
        }
      };

      render() {
        const { tos } = this.props;
        const { currentTos: currentTosId } = this.state;
        const termsOfServices = tos.value;
        const currentTermsOfServices = termsOfServices && termsOfServices[currentTosId];
        const loaded = termsOfServices && !tos.pending && tos.fulfilled;
        const htmlTransformCallback = (node) => {
          if (node.type === 'tag' && node.name === 'a') {
            // eslint-disable-next-line no-param-reassign
            node.attribs.class = 'external';
          }
          return undefined;
        };

        return (
          <div>
            { (!loaded || !currentTermsOfServices) && (
            <div id="
optin_page_content" className="text-align-center">
              <Block className="row align-items-stretch text-align-center">
                <Col><Preloader size={50} /></Col>
              </Block>
            </div>
            )}
            { loaded && currentTermsOfServices && (
            <div id="optin_page_content" className="text-align-center">
              <h1>
                <FormattedMessage id="press_yui_tos_subtitle" values={{ from: currentTosId + 1, to: termsOfServices.length }} />
              </h1>
              <BlockTitle>
                {ReactHtmlParser(
                  currentTermsOfServices.title,
                  { transform: htmlTransformCallback },
                )}
              </BlockTitle>
              <Block strong inset>
                <div className="tos_content">
                  {ReactHtmlParser(
                    currentTermsOfServices.html,
                    { transform: htmlTransformCallback },
                  )}
                </div>
              </Block>
              <Fab position="right-bottom" slot="fixed" color="pink" onClick={() => this.handleNext()}>
                {currentTosId + 1 === termsOfServices.length &&
                <Icon ios="f7:check" aurora="f7:check" md="material:check" />}
                {currentTosId !== termsOfServices.length &&
                <Icon ios="f7:chevron_right" aurora="f7:chevron_right" md="material:chevron_right" />}
              </Fab>
              {currentTosId > 0 && (
              <Fab position="left-bottom" slot="fixed" color="pink" onClick={() => this.setState({ currentTos: currentTosId - 1 })}>
                <Icon ios="f7:chevron_left" aurora="f7:chevron_left" md="material:chevron_left" />
              </Fab>
              )}
            </div>
            )}
          </div>
        );
      }
    }

    export default connect.defaults(new API())((props, context) => {
      const { apiURL, userId } = context;
      return {
        tos: {
          url: new URL(`${apiURL}/tos?outdated=false&required=true`),
        },
        agreeTosFunc: (tos) => ({
          agreeTos: {
            body: JSON.stringify({ optIn: tos }),
            context,
            force: true,
            method: 'PUT',
            url: new URL(`${apiURL}/users/${userId}/optin`),
          },
        }),
      };
    })(TermsOfServices);

我的OptInPage组件:

import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import {
  Link,
  NavRight,
  Navbar,
  Page,
  Popup,
} from 'framework7-react';
import { FormattedMessage, intlShape } from 'react-intl';
import './OptInPage.scss';
import TermsOfServices from '../components/TermsOfServices';

class OptinPage extends PureComponent {
  static propTypes = {
    logout: PropTypes.func.isRequired,
    opened: PropTypes.bool.isRequired,
  };

  static contextTypes = {
    intl: intlShape,
    logout: PropTypes.func,
  };

  render() {
    const { opened, logout } = this.props;
    const { intl } = this.context;
    const { formatMessage } = intl;

    return (
      <Popup opened={opened} className="demo-popup-swipe" tabletFullscreen>
        <Page id="optin_page">
          <Navbar title={formatMessage({ id: 'press_yui_tos_title' })}>
            <NavRight>
              <Link onClick={() => logout()}>
                <FormattedMessage id="press_yui_comments_popup_edit_close" />
              </Link>
            </NavRight>
          </Navbar>
        </Page>
        <TermsOfServices onSucceeded={() => { onSucceeded(); }} />
      </Popup>
    );
  }
}

export default OptinPage;
javascript reactjs components state
1个回答
0
投票
  1. 在父组件中创建状态。
  2. 此外,创建一个可以更改创建状态的函数。
  3. 将此功能传递给子组件。
  4. 在子组件中,您可以使用此功能更改父组件状态。
© www.soinside.com 2019 - 2024. All rights reserved.