【问题标题】:Accessing a function/state of a component in a wrapping HOC在包装 HOC 中访问组件的功能/状态
【发布时间】:2017-12-07 15:39:21
【问题描述】:

所以我有一个组件 A(扩展 React.component),它被一个更高阶的组件 B 包裹。

在组件 B 的方法中,我需要为 A 设置状态,或者在 A 中调用一个函数(以便它可以执行 setState) - 这通常是如何完成的?

我可以在此处粘贴实际代码,但我认为如果有处理这种情况的标准方法可能会使事情复杂化。

编辑:这里的代码 - isOpen 需要改变模态关闭,它需要改变 handleSubmit....

import React from 'react';
import Modal from 'react-modal';
import { withFormik, Form, Field } from 'formik';
import Yup from 'yup';

// first part of Formik integration
const formikEnhancer = withFormik({
  mapPropsToValues(props) {
    return {
      personName: props.email || '',
      personSurname: props.surname || '',
      personCongregation: props.congregation || ''
    }
  },
  validationSchema: Yup.object().shape({
    personName: Yup.string().required().min(1),
    personSurname: Yup.string().required().min(2),
    personCongregation: Yup.string().required().min(8)
  }),
  handleSubmit(values, {props, resetForm, setErrors, setSubmitting}) {
    submitNewPerson(values, {resetForm, setErrors, setSubmitting});
    props.testCall;
  }
});

function submitNewPerson(v, {resetForm, setErrors, setSubmitting}) {
  //e.preventDefault();

  congregations = [];
  congregations.push(v.personCongregation);

  const peep = {
    name: v.personName,
    surname: v.personSurname,
    congregations: congregations//,
    //startDate: Number(e.target.componentStartDate.value),
    //endDate: Number(e.target.componentEndDate.value)
  };
    // do the db insert here and check for errors
    setSubmitting(false);
  });
};

class AddPerson extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      error: undefined,
      isOpen: false
    }
  }

  componentWillMount() {
    Modal.setAppElement('body');
  }

  renderCong() {
    // this just maps out a list of select options
  }

  render() {
    return (
      <div>
        <button className="button" onClick={()=> this.setState({isOpen:true, error:undefined})}>+ Add Person</button>
        <Modal isOpen={this.state.isOpen} contentLabel="Add Person"
          className = "boxed-view__box" overlayClassName="boxed-view boxed-view--modal">
          <Form className="boxed-view__form">
            <div>
              <Field type="text" name="personName" placeholder="Name" />
            </div>
            <div>
                <Field type="text" name="personSurname" placeholder="Surname" />
            </div>
            <div>
             <Field component="select" name="personCongregation" value={this.state.cong}>
                <option key="0" value="">- Select Option -</option>
                {this.renderCong()}
              </Field>
            </div>
            <button disabled={this.props.isSubmitting} className="button">Add Person</button>
            <button disabled={this.props.isSubmitting} type="button" className="button button--secondary" onClick={
              ()=> {
                this.props.resetForm();
                this.setState({isOpen:false});
              }}>Cancel</button>
          </Form>

        </Modal>
      </div>
    )
  };
};

【问题讨论】:

  • 在高阶组件中,您永远不需要在包装的组件上使用设置状态。与您的包装组件通信的唯一方法是使用props 您能否再描述一下您的功能用例?
  • B 不应该知道 A 的状态,A 应该提供一个 B 可以使用的待更新接口,这可以通过暴露 B 可以更新的 props 来完成,您可以添加 componentWillReceiveProps 方法A 根据收到的道具相应地更新状态。
  • 谢谢 - 有帮助的开始。所以 HOC (B) 是 Formik,它处理表单的验证和提交。在我的组件 (A) 中,我通过更改状态来打开模型以显示表单。然后Formik(B)有一个handleSubmit方法,当(A)提交时触发。如果提交成功,我需要通过更改状态来关闭模式 - 如果它是错误的,我需要通过更改状态来显示错误。
  • 为此,您应该让表单的父组件处理提交,它可以 (a) 触发来自表单组件的 onSubmit 回调,并且 (b) 保持成功/失败状态并传递后退作为要显示的道具。
  • 那么我认为状态应该在 B 内部处理,因为它是处理表单提交结果的一个,你可以在你的 B 状态中有一个 modalOpenhasError 属性,你可以在那里更新然后作为道具发送给 A 以便它可以更新自己的状态并隐藏/显示模式以及错误。

标签: javascript reactjs


【解决方案1】:

除非您控制组件 B,否则这是不可能的。一些流行的 HOC(比如 react-redux 中的 connect)有一种机制可以让你暴露封装的组件 A,但一般情况下并非如此。

通常最好不要这样做。如果需要从外部更改组件的状态,则应将其作为道具传入,并且“事实来源”应该是您的模型或视图模型。如果您使用的是 redux 之类的东西,请尝试将组件状态移动到 redux 状态,而不是调用 setState,而是使用 redux 操作/reducer 组合来更新它。

另一种方法是将状态上移一层,使其作为来自另一个组件(父组件)的 prop 传入,然后在该父组件中包含逻辑,尽管这不太灵活。

【讨论】:

    【解决方案2】:

    通常你将 props 发送到组件,然后你用一个函数处理这些 props,在这种情况下,用一些东西来设置状态,例如:

    class B extends React.Component{
    
       render(){
           <A toUpdateState={this.state.valueB} />
       }
    }
    
    class A extends React.Component{
    
       updateState(){
           this.setState({
               ...this.state,
               valueA: this.props.toUpdateState
           })
       }
    
       render(){...}
    }
    

    如果您在 B 组件中触发状态,A 组件将收到信息。

    还有其他方法可以做到这一点,但没有代码很难为您提供不同的解决方案。

    【讨论】:

    • 您提供的代码中的任何内容都无法确保在 A 收到新道具时调用 updateState,请更新您的答案。
    【解决方案3】:

    想出来 - 添加我自己的 onClick 处理程序(而不是允许 Formik 调用其 handleSubmit 方法) - 我的处理程序然后调用 Formik 的 handleSubmit 并根据返回值更改状态

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-09
      • 1970-01-01
      • 2021-04-15
      • 2020-06-23
      • 1970-01-01
      • 2020-01-11
      • 2021-01-14
      相关资源
      最近更新 更多