Кнопка Reactjs в родительском компоненте, которая отправляет форму Redux в дочернем компоненте - PullRequest
0 голосов
/ 02 октября 2018

У меня есть 4 вложенных компонента, <CompD> вложено в <CompC>, вложено в <CompB>, вложено в <CompA>.

<CompD> содержит Redux Form с onSubmit={onSubmit}с набором входов и кнопкой Сохранить с type="submit"

Фрагмент <CompD> в настоящее время с кнопкой:

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;

Я хочу вместо этого переместить эту кнопку на <CompA>Таким образом, кнопка в <CompA>, которая ведет себя точно так же, как кнопка в <CompD> и отправляет форму.

Фрагмент <CompA> с добавленной новой кнопкой:

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>
    )
  }
}

Как передать функцию handleSubmit(data) в <CompA данные из формы? Есть идеи, как мне это сделать?

Ответы [ 2 ]

0 голосов
/ 03 октября 2018

Вы можете поднять состояние отправки формы и логику с <CompD> до <CompA>, и можете использовать контекст реагирования для предоставления состояний формы и обработчиков в глубине до <CompD>, например, так:

    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>

Но это выглядит многословно, если форма отделена от кнопки отправки.Не уверен, почему у вас есть такая необходимость, но обычно лучше держать их вместе в одном компоненте.

0 голосов
/ 02 октября 2018

React Components используют реквизиты для общения друг с другом.Parent -> Child проходит через props, Child -> 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>
...