Подтвердить что ты не робот

Как подключить привязки редукционной формы к входам формы

redux-form - очень привлекательная библиотека для обеспечения привязок редукции для форм в реагирующем приложении, что должно быть супер-удобным. К сожалению, используя собственные примеры библиотеки, я не могу фактически связать что-либо, что очень удобно.

Я пытаюсь использовать образец кода на сайте проекта и нахожу несколько препятствий, несмотря на попытку воспроизвести его добросовестно. Где я неправильно интерпретирую этот API? Сменился ли API с момента написания демо-кода? Не хватает ли какой-либо критической и очевидной части знаний о скидках?

Проблема 1: подпись для метода handleSubmit должна быть handleSubmit(data). Но handleSubmit в настоящее время получает только действие React syntEvent из действия submit и никаких данных. (Фактически, используя написанный пример, было отправлено два отдельных события, по-видимому, из-за сложного действия onSubmit в форме и onClick на кнопке.) Откуда берутся эти данные, и почему я не могу передать его обработчику?

Проблема 2: существует критический объект fields, который должен быть определен в родительской форме и указан в качестве опоры для вашей формы. К сожалению, форма этого объекта fields не объясняется в документах, а также в их целях. Является ли это по существу первоначальным "государственным" объектом? Простой контейнер объекта для редукционной формы для использования во время выполнения для ошибок и т.д.? Я попытался остановить ошибку, сопоставив реквизиты fields с именами полей в connectReduxForm, но поскольку данные не являются обязательными, я предполагаю, что это не правильная форма.

Проблема 3. Предполагается, что поля должны быть привязаны к обработчикам для onBlur и onChange, поэтому они соответствующим образом обновляют хранилище. Это никогда не происходит. (Что мы можем видеть благодаря инструментам Redux dev. Однако handleSubmit успешно отправляет действие initialize, что говорит о том, что все хранилище, редуктор и другая базовая сантехника работают.)

Проблема 4: validateContact запускается один раз на init, но никогда больше.

Это, к сожалению, слишком сложно для простого скрипта, но весь репо (он просто базовый ReduxStarterApp, плюс эта форма POC) доступен здесь.

И вот внешний компонент:

import React       from 'react';
import { connect } from 'react-redux';
import {initialize} from 'redux-form';

import ContactForm from '../components/simple-form/SimpleForm.js';

const mapStateToProps = (state) => ({
  counter : state.counter
});
export class HomeView extends React.Component {
  static propTypes = {
    dispatch : React.PropTypes.func.isRequired,
    counter  : React.PropTypes.number
  }

  constructor () {
    super();
  }
  handleSubmit(event, data) {
    event.preventDefault();
    console.log(event); // this should be the data, but is an event
    console.log(data); // no data here, either...
    console.log('Submission received!', data);
    this.props.dispatch(initialize('contact', {})); // clear form: THIS works
    return false;
  }

  _increment () {
    this.props.dispatch({ type : 'COUNTER_INCREMENT' });
  }


  render () {
    const fields = {
      name: '',
      address: '',
      phone: ''
    };

    return (
      <div className='container text-center'>
        <h1>Welcome to the React Redux Starter Kit</h1>
        <h2>Sample Counter: {this.props.counter}</h2>
        <button className='btn btn-default'
                onClick={::this._increment}>
          Increment
        </button>
        <ContactForm handleSubmit={this.handleSubmit.bind(this)} fields={fields} />
      </div>
    );
  }
}

export default connect(mapStateToProps)(HomeView);

И внутренняя составляющая формы:

import React, {Component, PropTypes} from 'react';
import {connectReduxForm} from 'redux-form';

function validateContact(data) {
  console.log("validating");
  console.log(data);
  const errors = {};
  if (!data.name) {
    errors.name = 'Required';
  }
  if (data.address && data.address.length > 50) {
    errors.address = 'Must be fewer than 50 characters';
  }
  if (!data.phone) {
    errors.phone = 'Required';
  } else if (!/\d{3}-\d{3}-\d{4}/.test(data.phone)) {
    errors.phone = 'Phone must match the form "999-999-9999"';
  }
  return errors;
}

class ContactForm extends Component {
  static propTypes = {
    fields: PropTypes.object.isRequired,
    handleSubmit: PropTypes.func.isRequired
  }

  render() {
    const { fields: {name, address, phone}, handleSubmit } = this.props;
    return (
      <form onSubmit={handleSubmit}>
        <label>Name</label>
        <input type="text" {...name}/>     {/* will pass value, onBlur and onChange */}
        {name.error && name.touched && <div>{name.error}</div>}

        <label>Address</label>
        <input type="text" {...address}/>  {/* will pass value, onBlur and onChange*/}
        {address.error && address.touched && <div>{address.error}</div>}

        <label>Phone</label>
        <input type="text" {...phone}/>    {/* will pass value, onBlur and onChange */}
        {phone.error && phone.touched && <div>{phone.error}</div>}

        <button type='submit'>Submit</button>
      </form>
    );
  }
}

// apply connectReduxForm() and include synchronous validation
ContactForm = connectReduxForm({
  form: 'contact',                      // the name of your form and the key to
                                        // where your form state will be mounted
  fields: ['name', 'address', 'phone'], // a list of all your fields in your form
  validate: validateContact             // a synchronous validation function
})(ContactForm);

// export the wrapped component
export default ContactForm;
4b9b3361

Ответ 1

connectReduxForm обертывает ваш компонент другим компонентом, который обрабатывает передачу в реквизитах fields и handleSubmit, но вы дуете их, передавая их в себе.

Попробуйте это вместо этого (переименовали prop на onSubmit):

<ContactForm onSubmit={this.handleSubmit.bind(this)}/>

И в ContactForm, передайте свой собственный обработчик отправки в функцию handleSubmit, предоставленную формой redux:

<form onSubmit={handleSubmit(this.props.onSubmit)}>

Я рекомендую использовать "Реагировать инструменты разработчика" , чтобы лучше понять, что происходит - вы увидите, как wrapx-форма обертывает ваш компонент и передает ему целую кучу реквизитов, как описано в ее README.

состав редукционной формы в инструментах разработчика React

Ответ 2

Спасибо Jonny Buchanan, который рассмотрел самый важный момент: не делайте так, как я, и автоматически предполагаем, что если в вашем компоненте требуются реквизиты, вы должны сами предоставить их. Вся точка функции более высокого порядка, которая connectReduxForm, должна обеспечить их в компоненте обертки. Исправление, которое немедленно дало мне обработчики событий, для всего, кроме Submit.

Другой критический надзор был здесь:

ПРИМЕЧАНИЕ. Если вы не выполняете соединение() самостоятельно (и это рекомендуется, чтобы вы этого не сделали, если у вас нет расширенного варианта использования, требует этого), вы должны установить редуктор в форме.

Я не понял этого. Но реализация здесь:

import { createStore, combineReducers } from 'redux';
import { reducer as formReducer } from 'redux-form';
const reducers = {
  // ... your other reducers here ...
  form: formReducer           // <---- Mounted at 'form'
}
const reducer = combineReducers(reducers);
const store = createStore(reducer);

В formReducer нельзя ссылаться на formReducer, но требуется синтаксис form: formReducer. Это была коррекция, которая правильно включила handleSubmit.