【问题标题】:Reactjs button in Parent component which submits Redux Form in Child Component父组件中的 Reactjs 按钮,在子组件中提交 Redux 表单
【发布时间】:2019-03-07 18:37:59
【问题描述】:

我有 4 个嵌套组件,<CompD> 嵌套在 <CompC> 中,<CompB> 嵌套在 <CompB> 中,<CompA> 中嵌套。

<CompD> 包含一个带有 onSubmit={onSubmit} 的 Redux 表单,带有一堆输入和一个带有 type="submit" 的保存按钮

<CompD> 的 sn-p 当前带有按钮:

const propTypes = {
  firstName: PropTypes.string,
  secondName: PropTypes.string
};

const defaultTypes = {
  firstName = " ",
  secondName = " "
};

const PollForm = ({
  firstName,
  secondName
}) => (
  <Form onSubmit={onSubmit}>
    .
    .
    <button type="submit">
      'Save'
    </button>
  </Form>
);

PollForm.propTypes = propTypes;
PollForm.defaultProps = defaultProps;

export default PollForm;

我想将此按钮移至&lt;CompA&gt;,因此&lt;CompA&gt; 中的按钮的行为方式与&lt;CompD&gt; 中的按钮完全相同并提交表单。

&lt;CompA&gt; 的 sn-p 添加了一个新按钮:

const propTypes = {
  onSubmit: PropTypes.func, ...
};

const defaultTypes = {
  onSubmit: () = {}, ...
};

class Config extends Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this); ...
  }

  handleSubmit(data) {
    this.props.onSubmit(data);
  }

  render() {
    const {
    } = this.props;

    return (
      .
      .
      <button onClick={onSubmit}>
        'Save'
      </button>
    )
  }
}

如何在&lt;CompA 中传递handleSubmit(data) 函数中的表单数据 有什么想法可以做到这一点吗?

【问题讨论】:

  • 您想获取 CompA 中的按钮并将表单保留在 CompD 中吗?
  • 您的意思是点击&lt;CompA&gt; 中的按钮,然后以某种方式触发&lt;CompD&gt; 中的Form 的onSubmit 事件,对吧?
  • @NguyễnThanhTú 是的,这是正确的
  • @IvanBurnaev 是的

标签: javascript reactjs forms redux components


【解决方案1】:

React 组件使用 props 相互通信。 Parent -&gt; Child 通过propsChild -&gt; Parent 通过callback props。另一种方法是使用新的Context API。如果你有一个非常深的嵌套结构会更好。

下面我展示了如何通过道具来完成。

class CompB extends React.Component {
  state = {
    name: "John Doe",
    email: "john@doe.com"
  }
  
  handleChange = e => {
    const {name, value} = e.target;       
    this.setState({[name]: value})
  }
  
  handleSubmit = e => {
    e.preventDefault();
   
    this.submit(this.state)
  }
  
  submit = (data) => {
    console.log("submitted", data, +new Date());
    
    this.props.onSubmit(data);
  }
  
  componentDidUpdate (oldProps) {
    if (!oldProps.shouldSubmit && this.props.shouldSubmit){
      this.submit(this.state);
    }
  }
  
  render () {
    const { name, email } = this.state; 
 
    return (
      <form onChange={this.handleChange} onSubmit={this.handleSubmit}>
        <div>
          <label>
            Name
            <input name="name" type="text" value={name} />
          </label>
        </div>

        <div>
          <label>
            Email
            <input name="email" type="email" value={email} />
          </label>
        </div>
      </form>
    )    
  }
}

class CompA extends React.Component { 
  state = {
    shouldSubmit: false,
  }
  
  submit = () => {
    this.setState({shouldSubmit: true})
  }
  
  handleSubmit = () => {
    this.setState({shouldSubmit: false})
  }
  
  render () {
    const {shouldSubmit} = this.state;
    
    return (
      <div>      
        <CompB 
          shouldSubmit={shouldSubmit} 
          onSubmit={this.handleSubmit}
        />
        
        <button 
          type="button" 
          onClick={this.submit}
        >
          Submit
        </button>
      </div>
    )
  }
}


ReactDOM.render(<CompA />, document.querySelector("#root"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

【讨论】:

  • 谢谢你的详细回答,我已经编辑了我的帖子以包含代码sn-ps,你能看看
  • 你想把数据保存在&lt;CompD /&gt;吗?
  • 我不确定,但我想将Form 保留在那里,这是否意味着数据也应该保留在那里?
  • 谢谢会检查,如果它有区别,我正在使用 Redux 表单并将状态映射到道具
【解决方案2】:

您可以将表单提交状态和逻辑从 &lt;CompD&gt; 提升到 &lt;CompA&gt;,并且可以使用 React Context 提供表单状态和处理程序深入到 &lt;CompD&gt;,例如:

    import React from 'react';
    import ReactDOM from 'react-dom';

    const FormContext = React.createContext();

    function CompB({ children }) {
      return <div id="B">{children}</div>;
    }
    function CompC({ children }) {
      return <div id="C">{children}</div>;
    }

    function CompD() {
      return (
        <FormContext.Consumer>
          {({ onSubmit, onChange, name }) => {
            return (
              <form onSubmit={onSubmit}>
                <label>
                  Name:
                  <input type="text" value={name} onChange={onChange} />
                </label>
                <input type="submit" value="submit-input" />
              </form>
            );
          }}
        </FormContext.Consumer>
      );
    }

    class CompA extends React.Component {
      onChange = ({ target: { value } }) => {
        this.setState({ name: value });
      };
      onSubmit = event => {
        event.preventDefault();
        console.log('Submitting name: ', this.state.name);
      };
      state = {
        name: 'defaultName',
        onSubmit: this.onSubmit,
        onChange: this.onChange,
      };
      render() {
        return (
          <FormContext.Provider value={this.state}>
            <CompB>
              <CompC>
                <CompD />
              </CompC>
            </CompB>
            <button name="submit" onClick={this.onSubmit}>submit-btn<button/>
          </FormContext.Provider>
        );
      }
    }

    ReactDOM.render(
        <CompA />,
        document.getElementById('root'),
      );
<!doctype html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>React App</title>
</head>

<body>
  <div id="root"></div>
  
</body>

</html>

但是将表单与提交按钮分开看起来确实很冗长。不知道为什么你有这样的需求,但通常最好将它们放在一个组件中。

【讨论】:

  • 谢谢你的详细回答,我已经编辑了我的帖子以包含代码sn-ps,你能看看
  • 您好,我已阅读您更新的 sn-ps。如果在 之间有 甚至更多层,您可以选择使用 React Context,如我在答案的代码示例中所示;或者如果没有那么多层,您可以将onSubmitonChange 等从 传递到 ,就像显示的其他答案一样。
猜你喜欢
  • 2017-10-19
  • 2019-09-27
  • 2017-11-01
  • 2022-01-25
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 2019-01-03
  • 2020-03-26
相关资源
最近更新 更多