Merge pull request #17496 from bancek/redux-form-improvements

redux-form: Add action types, fix reducer plugin, add StrictFormProps
This commit is contained in:
Paul van Brenk
2017-06-29 13:39:38 -07:00
committed by GitHub
6 changed files with 139 additions and 65 deletions

View File

@@ -1,6 +1,6 @@
// Type definitions for redux-form 6.6
// Project: https://github.com/erikras/redux-form
// Definitions by: Carson Full <https://github.com/carsonf>, Daniel Lytkin <https://github.com/aikoven>, Karol Janyst <https://github.com/LKay>
// Definitions by: Carson Full <https://github.com/carsonf>, Daniel Lytkin <https://github.com/aikoven>, Karol Janyst <https://github.com/LKay>, Luka Zakrajsek <https://github.com/bancek>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.3
@@ -41,5 +41,6 @@ export * from "./lib/FieldArray";
export * from "./lib/Form";
export * from "./lib/FormSection";
export * from "./lib/actions";
export * from "./lib/actionTypes";
export * from "./lib/reducer";
export * from "./lib/selectors";

37
types/redux-form/lib/actionTypes.d.ts vendored Normal file
View File

@@ -0,0 +1,37 @@
export interface ActionTypes {
ARRAY_INSERT: string;
ARRAY_MOVE: string;
ARRAY_POP: string;
ARRAY_PUSH: string;
ARRAY_REMOVE: string;
ARRAY_REMOVE_ALL: string;
ARRAY_SHIFT: string;
ARRAY_SPLICE: string;
ARRAY_UNSHIFT: string;
ARRAY_SWAP: string;
AUTOFILL: string;
BLUR: string;
CHANGE: string;
CLEAR_SUBMIT: string;
CLEAR_SUBMIT_ERRORS: string;
CLEAR_ASYNC_ERROR: string;
DESTROY: string;
FOCUS: string;
INITIALIZE: string;
REGISTER_FIELD: string;
RESET: string;
SET_SUBMIT_FAILED: string;
SET_SUBMIT_SUCCEEDED: string;
START_ASYNC_VALIDATION: string;
START_SUBMIT: string;
STOP_ASYNC_VALIDATION: string;
STOP_SUBMIT: string;
SUBMIT: string;
TOUCH: string;
UNREGISTER_FIELD: string;
UNTOUCH: string;
UPDATE_SYNC_ERRORS: string;
UPDATE_SYNC_WARNINGS: string;
}
export const actionTypes: ActionTypes;

View File

@@ -1,81 +1,87 @@
import { Action } from "redux";
import { FormErrors, FormWarnings, FieldType } from "../index";
export interface FormAction extends Action {
meta: {
form: string;
};
}
/**
* Inserts an item into a field array at the specified index
*/
export function arrayInsert(form: string, field: string, index: number, value: any): Action;
export function arrayInsert(form: string, field: string, index: number, value: any): FormAction;
/**
* Moves an item from one index in the array to another. In effect, it performs a remove and an
* insert, so the item already at the `to` position will be bumped to a higher index, not overwritten.
*/
export function arrayMove(form: string, field: string, from: number, to: number): Action;
export function arrayMove(form: string, field: string, from: number, to: number): FormAction;
/**
* Removes an item from the end of a field array
*/
export function arrayPop(form: string, field: string): Action;
export function arrayPop(form: string, field: string): FormAction;
/**
* Appends an item to the end of a field array
*/
export function arrayPush(form: string, field: string, value: any): Action;
export function arrayPush(form: string, field: string, value: any): FormAction;
/**
* Removes an item at the specified index from a field array
*/
export function arrayRemove(form: string, field: string, index: number): Action;
export function arrayRemove(form: string, field: string, index: number): FormAction;
/**
* Removes all items from a field array
*/
export function arrayRemoveAll(form: string, field: string): Action;
export function arrayRemoveAll(form: string, field: string): FormAction;
/**
* Removes an item from the beginning of a field array
*/
export function arrayShift(form: string, field: string): Action;
export function arrayShift(form: string, field: string): FormAction;
/**
* ADVANCED USAGE - Inserts and/or removes items from a field array. Works similarly to Array.splice.
*/
export function arraySplice(form: string, field: string, index: number, removeNum: number, value: any): Action;
export function arraySplice(form: string, field: string, index: number, removeNum: number, value: any): FormAction;
/**
* Swaps two items at the specified indexes in a field array
*/
export function arraySwap(form: string, field: string, indexA: number, indexB: number): Action;
export function arraySwap(form: string, field: string, indexA: number, indexB: number): FormAction;
/**
* Inserts an item at the beginning of a field array
*/
export function arrayUnshift(form: string, field: string, value: any): Action;
export function arrayUnshift(form: string, field: string, value: any): FormAction;
/**
* Saves the value to the field and sets its `autofilled` property to `true`.
*/
export function autofill(form: string, field: string, value: any): Action;
export function autofill(form: string, field: string, value: any): FormAction;
/**
* Saves the value to the field
*/
export function blur(form: string, field: string, value: any): Action;
export function blur(form: string, field: string, value: any): FormAction;
/**
* Saves the value to the field
*/
export function change(form: string, field: string, value: any): Action;
export function change(form: string, field: string, value: any): FormAction;
/**
* Destroys the form, removing all it's state
*/
export function destroy(...form: string[]): Action;
export function destroy(...form: string[]): FormAction;
/**
* Marks the given field as active and visited
*/
export function focus(form: string, field: string): Action;
export function focus(form: string, field: string): FormAction;
/**
* Sets the initial values in the form with which future data values will be compared to calculate dirty and pristine.
@@ -88,67 +94,67 @@ interface InitializeOptions {
keepSubmitSucceeded: boolean;
}
export function initialize(form: string, data: any, keepDirty?: boolean | InitializeOptions, options?: InitializeOptions): Action;
export function initialize(form: string, data: any, keepDirty?: boolean | InitializeOptions, options?: InitializeOptions): FormAction;
/**
* Registers a field with the form.
*/
export function registerField(form: string, name: string, type: FieldType): Action;
export function registerField(form: string, name: string, type: FieldType): FormAction;
/**
* Resets the values in the form back to the values past in with the most recent initialize action.
*/
export function reset(form: string): Action;
export function reset(form: string): FormAction;
/**
* Flips the asyncValidating flag true
*/
export function startAsyncValidation(form: string): Action;
export function startAsyncValidation(form: string): FormAction;
/**
* Flips the asyncValidating flag false and populates asyncError for each field.
*/
export function stopAsyncValidation(form: string, errors?: any): Action;
export function stopAsyncValidation(form: string, errors?: any): FormAction;
export function setSubmitFailed(form: string, ...fields: string[]): Action;
export function setSubmitFailed(form: string, ...fields: string[]): FormAction;
export function setSubmitSucceeded(form: string, ...fields: string[]): Action;
export function setSubmitSucceeded(form: string, ...fields: string[]): FormAction;
/**
* Flips the submitting flag true.
*/
export function startSubmit(form: string): Action;
export function startSubmit(form: string): FormAction;
/**
* Flips the submitting flag false and populates submitError for each field.
*/
export function stopSubmit(form: string, errors?: any): Action;
export function stopSubmit(form: string, errors?: any): FormAction;
/**
* Flips the asyncValidating flag false and populates asyncError for each field.
*/
export function stopAsyncValidation(form: string, errors?: any): Action;
export function stopAsyncValidation(form: string, errors?: any): FormAction;
/**
* Triggers a submission of the specified form.
*/
export function submit(form: string): Action;
export function submit(form: string): FormAction;
/**
* Marks all the fields passed in as touched.
*/
export function touch(form: string, ...fields: string[]): Action;
export function touch(form: string, ...fields: string[]): FormAction;
/**
* Unregisters a field with the form.
*/
export function unregisterField(form: string, name: string): Action;
export function unregisterField(form: string, name: string): FormAction;
/**
* Resets the 'touched' flag for all the fields passed in.
*/
export function untouch(form: string, ...fields: string[]): Action;
export function untouch(form: string, ...fields: string[]): FormAction;
export function updateSyncErrors(from: string, syncErrors: FormErrors<FormData>, error: any): Action;
export function updateSyncErrors(from: string, syncErrors: FormErrors<FormData>, error: any): FormAction;
export function updateSyncWarnings(form: string, syncWarnings: FormWarnings<FormData>, warning: any): Action;
export function updateSyncWarnings(form: string, syncWarnings: FormWarnings<FormData>, warning: any): FormAction;

View File

@@ -1,9 +1,7 @@
import { Action, Reducer } from "redux";
import { FieldType } from "../index";
export function reducer(state: FormStateMap, action: Action): FormStateMap & FormReducer;
export interface FormReducer {
export interface FormReducer extends Reducer<FormStateMap> {
/**
* Returns a form reducer that will also pass each action through
* additional reducers specified. The parameter should be an object mapping
@@ -11,9 +9,11 @@ export interface FormReducer {
* passed to each reducer will only be the slice that pertains to that
* form.
*/
plugin(reducers: FormReducerMapObject): Reducer<any>;
plugin(reducers: FormReducerMapObject): Reducer<FormStateMap>;
}
export const reducer: FormReducer;
export interface FormReducerMapObject {
[formName: string]: Reducer<any>;
}

View File

@@ -339,18 +339,19 @@ export interface FormComponent<FormData extends DataShape, P, S> extends Compone
/**
* These are the props that will be passed to your form component.
* Your form component's props can extend this interface.
* Your form component's props can extend this interface if you want
* to use strict checks.
*/
export interface FormProps<FormData extends DataShape, P, S> {
export interface StrictFormProps<FormData extends DataShape, P, S> {
/**
* true if any of the fields have been marked as touched, false otherwise.
*/
anyTouched?: boolean;
anyTouched: boolean;
/**
* A set of pre-bound action creators for you to operate on array fields in your form.
*/
array?: {
array: {
/**
* Inserts a value into the given array field in your form.
*/
@@ -407,7 +408,7 @@ export interface FormProps<FormData extends DataShape, P, S> {
* A function that may be called to initiate asynchronous validation if
* asynchronous validation is enabled.
*/
asyncValidate?: () => void;
asyncValidate: () => void;
/**
* This value will be either:
@@ -415,54 +416,54 @@ export interface FormProps<FormData extends DataShape, P, S> {
* - true - Asynchronous validation is currently running in preparation to submit a form
* - a string - The name of the field that just blurred to trigger asynchronous validation
*/
asyncValidating?: string | boolean;
asyncValidating: string | boolean;
/**
* Sets the value and marks the field as autofilled in the Redux Store. This is useful when a field
* needs to be set programmatically, but in a way that lets the user know (via a styling change using
* the autofilled prop in Field) that it has been autofilled for them programmatically.
*/
autofill?(field: string, value: FieldValue): void;
autofill(field: string, value: FieldValue): void;
/**
* Marks a field as blurred in the Redux store.
*/
blur?(field: string, value: FieldValue): void;
blur(field: string, value: FieldValue): void;
/**
* Changes the value of a field in the Redux store.
*/
change?(field: string, value: FieldValue): void;
change(field: string, value: FieldValue): void;
/**
* Clear async error of a field in the Redux store.
*/
clearAsyncError?(field: string): void;
clearAsyncError(field: string): void;
/**
* Destroys the form state in the Redux store. By default, this will be
* called for you in componentWillUnmount().
*/
destroy?(): void;
destroy(): void;
/**
* true if the form data has changed from its initialized values. Opposite
* of pristine.
*/
dirty?: boolean;
dirty: boolean;
/**
* A generic error for the entire form given by the _error key in the
* result from the synchronous validation function, the asynchronous
* validation, or the rejected promise from onSubmit.
*/
error?: string;
error: string;
/**
* The form name that you gave to the reduxForm() decorator or the prop you
* passed in to your decorated form component.
*/
form?: string;
form: string;
/**
* A function meant to be passed to <form onSubmit={handleSubmit}> or to
@@ -484,79 +485,87 @@ export interface FormProps<FormData extends DataShape, P, S> {
* may pass that as if it were the error for a field called _error, and
* it will be given as the error prop.
*/
handleSubmit?(event: SyntheticEvent<any>): void; // same as ReactEventHandler
handleSubmit(event: SyntheticEvent<any>): void; // same as ReactEventHandler
handleSubmit?(submit: SubmitHandler<FormData, P, S>): ReactEventHandler<any>;
handleSubmit(submit: SubmitHandler<FormData, P, S>): ReactEventHandler<any>;
/**
* Initializes the form data to the given values. All dirty and pristine
* state will be determined by comparing the current data with these
* initialized values.
*/
initialize?(data: FormData): void;
initialize(data: FormData): void;
/**
* The same initialValues object passed to reduxForm to initialize the form data.
*/
initialValues?: Partial<FormData>;
initialValues: Partial<FormData>;
/**
* true if the form has validation errors. Opposite of valid.
*/
invalid?: boolean;
invalid: boolean;
/**
* true if the form data is the same as its initialized values. Opposite
* of dirty.
*/
pristine?: boolean;
pristine: boolean;
/**
* Resets all the values in the form to the initialized state, making it
* pristine again.
*/
reset?(): void;
reset(): void;
/**
* Whether or not your form is currently submitting. This prop will only
* work if you have passed an onSubmit function that returns a promise. It
* will be true until the promise is resolved or rejected.
*/
submitting?: boolean;
submitting: boolean;
/**
* Starts as false. If onSubmit is called, and fails to submit for any
* reason, submitFailed will be set to true. A subsequent successful
* submit will set it back to false.
*/
submitFailed?: boolean;
submitFailed: boolean;
/**
* Starts as false. If onSubmit is called, and succeed to submit,
* submitSucceeded will be set to true. A subsequent unsuccessful
* submit will set it back to false.
*/
submitSucceeded?: boolean;
submitSucceeded: boolean;
/**
* Marks the given fields as "touched" to show errors.
*/
touch?(...field: string[]): void;
touch(...field: string[]): void;
/**
* Clears the "touched" flag for the given fields
*/
untouch?(...field: string[]): void;
untouch(...field: string[]): void;
/**
* true if the form passes validation (has no validation errors). Opposite
* of invalid.
*/
valid?: boolean;
valid: boolean;
/**
* A generic warning for the entire form given by the `_warning` key in the result from the
* synchronous warning function.
*/
warning?: string;
warning: string;
}
/**
* These are the props that will be passed to your form component.
* Your form component's props can extend this interface.
*/
export interface FormProps<FormData extends DataShape, P, S> extends Partial<StrictFormProps<FormData, P, S>> {
}

View File

@@ -1,6 +1,7 @@
import * as React from 'react';
import { Component } from 'react';
import { Field, GenericField, reduxForm, WrappedFieldProps, BaseFieldProps, FormProps } from "redux-form";
import { Action } from 'redux';
import { Field, GenericField, reduxForm, WrappedFieldProps, BaseFieldProps, FormProps, FormAction, actionTypes, reducer } from "redux-form";
interface CustomComponentProps {
customProp: string;
@@ -141,3 +142,23 @@ const mapStateToProps = (state: any) => ({
initialValues: { firstName: state.account.data.firstName } // pull initial values from account reducer
} as {initialValues?: Partial<DataShape>});
const ConnectedDecoratedInitializeFromStateFormClass = connect(mapStateToProps)(DecoratedInitializeFromStateFormClass);
reducer({}, {
type: 'ACTION'
});
reducer.plugin({
myform: (state: any, action: FormAction) => {
if (action.type === actionTypes.CHANGE && action.meta.form === 'securitySettings') {
return {
...state,
values: {
...state.values,
downloadLinkAutoPassword: true,
},
};
} else {
return state;
}
}
});