2017-09-06 3 views
1

J'ai un formulaire simple réagissant-redux. Je souhaite qu'il y ait un form.container.tsx et un form.component.tsx, où form.container.tsx contient toutes les connexions à l'état redux moins les champs. Je suis en train d'envelopper mon conteneur relient Réagissons-redux puis envelopper reduxForm à l'intérieur pour regarder quelque chose comme TypeScript, redux-form and connect:Typing redux forms v7 avec TypeScript et React

(idéal) form.container.tsx:

interface DummyFormContainerProps {} 

export const DummyFormContainer: React.SFC<DummyFormContainerProps> = props => { 
    const submitForm = (formValues: object) => { 
    alert(formValues); 
    }; 
    return (
    <DummyForm 
     onSubmit={submitForm} 
    /> 
); 
}; 

const mapStateToProps = (state: State) => ({}); 
const mapDispatchToProps = (dispatch: object) => { 
    return {}; 
}; 
const mergeProps = (stateProps: State, dispatchProps: object | null, ownProps: object | void) => 
    Object.assign({}, stateProps, dispatchProps, ownProps); 

const formConfiguration = { 
    form: 'dummy-form', 
    forceUnregisterOnUnmount: true 
}; 

export default connect(mapStateToProps, mapDispatchToProps)(
    reduxForm(formConfiguration)(DummyFormContainer) 
); 

Le ci-dessus ne fonctionne pas , mais si je prends la partie reduxForm(), je suis parti avec un récipient de travail sans intégration reduxForm:

(travail sans reduxForm) form.container.tsx:

export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(
    DummyFormContainer 
); 

Et j'ai essayé différentes variations avec reduxForms et de connexion, tout ne fonctionne pas actuellement:

(avec des classes) form.container.tsx:

export class DummyFormContainer extends React.Component<DummyFormContainerProps, void> { 
    submitForm = (formValues: object) => { 
    alert(formValues); 
    } 

    render() { 
    return (
     <DummyForm 
     onSubmit={this.submitForm} 
     /> 
    ); 
    } 
} 

const mapStateToProps = (state: State) => ({}); 
const mapDispatchToProps = (dispatch: object) => { 
    return {}; 
}; 
const mergeProps = (stateProps: State, dispatchProps: object | null, ownProps: object | void) => 
    Object.assign({}, stateProps, dispatchProps, ownProps); 

const formConfiguration = { 
    form: 'business-registration', 
}; 

export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(
    reduxForm(formConfiguration)(DummyFormContainer) // ERROR 
); 

erreur:

./src/modules/dummy-form/dummy-form.container.tsx 
(100,32): error TS2345: Argument of type 'typeof DummyFormContainer' is not assignable to parameter of type 'ComponentType<InjectedFormProps<{}, {}>>'. 
    Type 'typeof DummyFormContainer' is not assignable to type 'StatelessComponent<InjectedFormProps<{}, {}>>'. 
    Type 'typeof DummyFormContainer' provides no match for the signature '(props: InjectedFormProps<{}, {}> & { children?: ReactNode; }, context?: any): ReactElement<any> | null'. 

(avec des composants fonctionnels sans état) form.container.tsx:

export const DummyFormContainer: React.SFC<DummyFormContainerProps> = props => { 
    const submitForm = (formValues: object) => { 
    alert(formValues); 
    }; 
    return (
    <DummyForm 
     onSubmit={submitForm} 
    /> 
); 
}; 

export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(
    reduxForm(formConfiguration)(DummyFormContainer) // ERROR 
); 

err ou:

./src/modules/dummy-form/dummy-form.container.tsx 
(100,3): error TS2345: Argument of type 'DecoratedComponentClass<{}, Partial<ConfigProps<{}, {}>>>' is not assignable to parameter of type 'ComponentType<(State & null & void) | (State & null & object) | (State & object & void) | (State ...'. 
    Type 'DecoratedComponentClass<{}, Partial<ConfigProps<{}, {}>>>' is not assignable to type 'StatelessComponent<(State & null & void) | (State & null & object) | (State & object & void) | (S...'. 
    Type 'DecoratedComponentClass<{}, Partial<ConfigProps<{}, {}>>>' provides no match for the signature '(props: (State & null & void & { children?: ReactNode; }) | (State & null & object & { children?: ReactNode; }) | (State & object & void & { children?: ReactNode; }) | (State & object & { children?: ReactNode; }), context?: any): ReactElement<any> | null'. 

Le form.component.tsx ressemble à ceci:

import * as React from 'react'; 
import Input from '../../components/input'; 

interface DummyFormProps { 
    onSubmit: (formValues: object) => void 
} 

export const DummyForm: React.SFC<DummyFormProps> =() => { 
    return (
    <div> 
     <h1>DummyForm (no state)</h1> 
     <form> 
     <Input inputType="primary" /> 
     </form> 
    </div> 
); 
}; 

export default DummyForm; 

Et l'entrée <> composant est un composant régulier React.

Est-ce que quelqu'un sait comment connecter correctement reduxForm et connect-redux's connect()?

Répondre

1

J'ai aussi couru sur cette question en essayant d'initialiser ma forme d'un état Redux, selon l'exemple https://redux-form.com/7.0.4/examples/initializefromstate/

J'ai fini par se déplacer en connectant le composant à un niveau supérieur, par exemple:

component.tsx:

interface DummyFormComponentProps {} extends InjectedFormProps 

const DummyFormComponent: React.SFC<DummyFormComponentProps> = props => { 
    return (
    <form onSubmit={props.handleSubmit}> 
     // Fields go here 
    </form> 
) 
} 

export const DummyForm = reduxForm({ 
    form: "dummy-form" 
})(DummyFormComponent) 

// Trying to connect here also gave errors with DecoratedComponentClass 

container.tsx:

interface DummyFormContainerProps {} extends Pick<InjectedFormProps, 
    "initialValues" 
> 

const submitForm = (formValues: object) => { 
    alert(formValues); 
}; 

const DummyFormContainer: React.SFC<DummyFormContainerProps> = props => { 
    return (
    <DummyForm 
     initialValues={props.initialValues} 
     onSubmit={submitForm} 
    /> 
) 
} 

const mapStateToProps = (state: State) => ({ 
    initialValues: {} 
}); 
const mapDispatchToProps = (dispatch: object) => { 
    return {}; 
}; 
export default connect(mapStateToProps, mapDispatchToProps)(DummyFormContainer) 
0

Ce que nous avons fini par faire était de fermer les yeux et passer outre les types par défaut avec un fichier de déclaration de type:

redux-forms.d.ts:

declare module 'redux-form' { 
    type anyProps = { [key: string]: {} } 
    function Field(): React.Component<anyProps>; 
    function reduxForm({}): <T>(c: T) => T 
    function reducer(): object 
    interface SubmissionError { 
    new(error?: {}) : Error; 
    } 
    function getFormValues(formName: string): (formName: {}) => {} 
    function stopSubmit(formName: string, errorObject?: {}): any 
    function isSubmitting(formName: string): any 
    function setSubmitFailed(formName: string): any 
    function setSubmitSucceeded(formName: string): any 
    function touch(formName: string): any 
    function clearSubmitErrors(formName: string): any 
    function getFormMeta(formName: string, ...fields: string[]): (state: {}) => {} 
    function getFormSyncErrors(formName: string): (state: {}) => {} 
    function getFormSubmitErrors(formName: string): (state: {}) => {} 
    function getFormNames(): any 
} 
+0

où placer ce fichier de type soit au niveau racine du projet, soit dans le dossier node_modules –

+0

Nous l'avons simplement placé dans src/typings/redux-forms.d.ts. Nous avons utilisé create-react-app avec les scripts Typescript de Microsoft. N'a pas modifié le package.json pour faire quoi que ce soit donc je crois que TypeScript ne fait que sélectionner des éléments dans le dossier src/et lire le mot-clé 'declare'. –

+0

quand je fais comme vous le dites. J'ai fait face à cette erreur ci-dessous. D: \ repositories \ tsproj \ reactjs-ts-form-demo \ modules_noeud \ @types \ redux-form \ lib \ selectors.d.ts (1,10): erreur TS2305: Module '' redux-form '' 'n'a aucun membre exporté' FormErrors '. Mes dépendances sont: https://jsfiddle.net/mglrahul/9qrn6gbn/1/ –

1

Je trouve que je suis en mesure de rejeter l'erreur en fournissant l'instruction de connexion avec vide TStateProps et TDispatchProps objets.

interface SampleFormData { 
    username: string; 
} 

interface SampleFormProps { 
    saveData: (data: SampleFormData) => void; 
} 

type AllSampleFormProps = SampleFormProps & InjectedFormProps<SampleFormData>; 

const SampleForm: React.SFC<AllSampleFormProps> = (props) => (
    <form onSubmit={props.handleSubmit(props.saveData)}> 
    <Field name="username" component="input" /> 
    </form> 
); 

const DecoratedSampleForm = reduxForm<SampleFormData>({ form: "sampleForm" })(SampleForm); 

export default connect<{},{}>(
() => ({}), 
    (dispatch) => ({ 
    saveData: (data: SampleFormData) => dispatch({ type: "SAVE_DATA", data }) 
    }) 
)(DecoratedSampleForm); 

Le seul inconvénient est que cela nous oblige à fournir aveuglément connecter des accessoires mais je sentais que c'était une solution plus élégante que d'écrire la déclaration d'une dérogation.

Pour remédier à cette lacune, j'ai été en mesure de valider les types en fournissant une connexion avec les interfaces correctes par rapport aux objets vides; Toutefois, cette méthode peut uniquement être effectuée temporairement pour vérifier les liaisons car elle ne résout pas l'erreur DecoratedComponentClass.

export default connect<{}, SampleFormProps, InjectedFormProps<SampleFormData>>(
() => ({}), 
    (dispatch) => ({ 
    saveData: (data: SampleFormData) => dispatch({ type: "SAVE_DATA", data }) 
    }) 
)(DecoratedSampleForm); 
0

J'ai eu le même problème et trouvé qu'il a été causé par « types de @/réagir-Redux », supprimer ce type fichier de définition et tout fonctionne comme on peut s'y attendre à sans autres effets secondaires/erreurs de type causé par ne pas avoir ce type-def-fichier.