2015-10-15 10 views
28

redux-form to bardzo interesująca biblioteka do dostarczania wiązań redux dla formularzy w aplikacji reagującej, która powinna być super-wygodna. Niestety, korzystając z własnych przykładów biblioteki, nie udaje mi się niczego powiązać, co jest super wygodne.Jak powiązać wiązania formularzy reduktorów z wejściami formularza

Próbuję użyć przykładowego kodu na stronie projektu i znaleźć wiele przeszkód, pomimo próby wiernego odtworzenia go. Gdzie błędnie interpretuję ten interfejs API? Czy interfejs API został przesunięty od czasu napisania kodu demo? Czy brakuje mi jakiejś krytycznej i oczywistej wiedzy na temat redux?

Problem 1: Podpis metody handleSubmit powinien być handleSubmit(data). Ale funkcja handleSubmit otrzymuje obecnie tylko komunikat React syntheticEvent z akcji przesyłania i brak danych. (W rzeczywistości, użycie napisanego na przyklad przykładu wysłało dwa osobne zdarzenia, pozornie z powodu ułożonej akcji onSubmit na formularzu i onClick na przycisku.) Skąd pochodzą te dane i dlaczego nie mogę tego zrobić? przekazać go do obsługi?

Problem 2: istnieje krytyczna fields obiekt, który musi być określony na formularzu rodzica i dostarczone jako rekwizyt do formularza. Niestety, kształt tego obiektu fields nie jest wyjaśniony w dokumentach ani w jego celu. Czy w gruncie rzeczy jest to początkowy obiekt "stanu"? Prosty kontener obiektowy dla formy redux do użycia w czasie wykonywania dla błędów itp.? Dostałem go, aby przestać robić błędy, dopasowując rekwizyty z fields do nazw pól w connectReduxForm, ale ponieważ dane nie są wiążące, zakładam, że nie jest to właściwy kształt.

Problem 3: Pola mają być automatycznie związana z obsługą dla onBlur i onChange, tak aby zaktualizować sklep odpowiednio. To się nigdy nie zdarza. (Co możemy zobaczyć dzięki dev-tools Redux Jednak handleSubmit powodzeniem wysyłki akcję initialize, co sugeruje, sklepu, reduktor, i inne podstawowe kanalizacja wszyscy pracujemy.).

Problem 4: validateContact jest wypalanie raz na init, ale nigdy więcej.

Jest to niestety zbyt skomplikowane na proste Fiddle, ale całe repo (to tylko podstawowe ReduxStarterApp, plus ten formularz POC) is available here.

I tu jest zewnętrzny komponent:

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

i wewnętrzną komponent forma:

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's 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; 
+1

Dziękuję za to skomplikowane pytanie! Miałem te same trudności i uważam, że dokumentacja formy redux i przykłady są skomplikowane i niekompletne. Dzięki pomocy twojej i @ Jonny Buchanana mogłem kontynuować (chociaż mam skomplikowaną strukturę danych i jeszcze nie skończyłem). Dodanie rozszerzenia [redux devtools extension] (https://github.com/zalmoxisus/redux-devtools-extension) również bardzo pomogło przy debugowaniu! –

Odpowiedz

23

connectReduxForm owija swój składnik z innym składnikiem, który obsługuje przechodzącej w fields i handleSubmit rekwizytów, ale odrzucasz je, przekazując je sobie.

Spróbuj zamiast (przemianowany na rekwizyt do onSubmit):

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

I ContactForm, pass your own submit handler to the handleSubmit function provided by redux-form:

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

Polecam pomocą React developer tools aby uzyskać lepszy obraz tego, co się dzieje - zobaczysz, jak redux-form otula twój komponent i passes it a whole bunch of props, as documented in its README.

redux-form composition in React developer tools

+2

Czy możesz zaktualizować link? Wszystkie odnośniki wskazują teraz stronę główną github 'redux-form'. – Mithril

8

Dzięki Jonny Buchanan, który pokryty najważniejszy punkt: nie rób jak ja i automatycznie zakładać, że jeśli rekwizyty są wymagane w składniku muszą musisz dostarczyć je samodzielnie. Cały punkt funkcji wyższego rzędu, czyli connectReduxForm, polega na zapewnieniu ich w komponencie opakowania. Naprawienie, które natychmiast dało mi obsługę zdarzeń, dla wszystkiego oprócz wysłania.

Drugim krytycznym niedopatrzenie było tutaj:

UWAGA - Jeśli nie robią connect() ing siebie (i to jest Zaleca się, aby nie zrobić, chyba że masz zaawansowany przypadek użycia tego wymaga tego), musisz zamontować reduktor na z formularza.

Nie zrozumiałem tego. Ale realizacja jest tutaj:

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 nie można odwoływać się w formReducer, ale wymaga składni form: formReducer. To była poprawka, która prawidłowo włączyła handleSubmit.

Powiązane problemy