【问题标题】:How can I pass the state from this child to parent component?如何将此子组件的状态传递给父组件?
【发布时间】:2020-06-21 08:49:56
【问题描述】:

我有 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】:

    请试试这个方法

    class OptIn extends Component{
       state = {}
    
       receiveChildState = (childState) => {
           console.log(childState)
       }
    
       render(){
          return(
              <TermsOfService receiveChildState={this.receiveChildState}/>
          );
       }
    }
    
    class TermsOfService extends Component{
      state = {
         x: 1
      }
    
      updateState = () => {
         const {x} = this.state;
         const {receiveChildState} = this.props;
         this.setState({x: x+1});
         receiveChildState(x+1);
      }
    
       render(){
          return(
              <button onClick={this.updateState}> Terms of service </button>
          );
       }
    }
    

    【讨论】:

      【解决方案2】:
      1. 在您的父组件中创建一个状态。
      2. 另外,创建一个可以更改创建状态的函数。
      3. 将此函数传递给子组件。
      4. 在您的子组件中,您可以使用此功能更改父组件 状态。

      【讨论】:

        猜你喜欢
        • 2019-04-02
        • 2019-08-15
        • 1970-01-01
        • 2014-12-18
        • 2019-02-17
        • 2017-05-31
        • 2020-07-04
        • 2022-07-15
        • 1970-01-01
        相关资源
        最近更新 更多