Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@shopify/react-form-state

Package Overview
Dependencies
Maintainers
11
Versions
146
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@shopify/react-form-state - npm Package Compare versions

Comparing version 0.5.6 to 0.6.0

10

CHANGELOG.md

@@ -7,5 +7,11 @@ # Changelog

## [0.6]
### Added
- You can control how `<FormState />` reacts to changes in the initialValue prop using onInitialValueChanged.
## [0.5]
## Added
### Added

@@ -16,3 +22,3 @@ - `<List />` supports `getChildKey` to provide custom `key`s for it's children. [#387](https://github.com/Shopify/quilt/pull/387)

## Fixed
### Fixed

@@ -19,0 +25,0 @@ - `<List />` no longer breaks on name generation.

@@ -33,2 +33,3 @@ import * as React from 'react';

validateOnSubmit?: boolean;
onInitialValuesChange?: 'reset-all' | 'reset-where-changed' | 'ignore';
children(form: FormDetails<Fields>): React.ReactNode;

@@ -45,3 +46,3 @@ }

static Nested: typeof Nested;
static getDerivedStateFromProps<T>(newProps: Props<T>, oldState?: State<T>): State<T> | null;
static getDerivedStateFromProps<T>(newProps: Props<T>, oldState: State<T>): State<T> | null;
state: State<Fields>;

@@ -54,2 +55,3 @@ private mounted;

validateForm(): Promise<{}>;
reset(): Promise<{}>;
private readonly dirty;

@@ -60,3 +62,2 @@ private readonly valid;

private submit;
private reset;
private fieldWithHandlers;

@@ -63,0 +64,0 @@ private updateField;

63

dist/FormState.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
/* eslint-disable no-case-declarations */
var React = tslib_1.__importStar(require("react"));

@@ -20,12 +21,17 @@ var isEqual_1 = tslib_1.__importDefault(require("lodash/isEqual"));

FormState.getDerivedStateFromProps = function (newProps, oldState) {
var newInitialValues = newProps.initialValues;
if (oldState == null) {
return createFormState(newInitialValues);
var initialValues = newProps.initialValues, onInitialValuesChange = newProps.onInitialValuesChange;
switch (onInitialValuesChange) {
case 'ignore':
return null;
case 'reset-where-changed':
return reconcileFormState(initialValues, oldState);
case 'reset-all':
default:
var oldInitialValues = initialValuesFromFields(oldState.fields);
var valuesMatch = isEqual_1.default(oldInitialValues, initialValues);
if (valuesMatch) {
return null;
}
return createFormState(initialValues);
}
var oldInitialValues = initialValuesFromFields(oldState.fields);
var shouldReinitialize = !isEqual_1.default(oldInitialValues, newInitialValues);
if (shouldReinitialize) {
return createFormState(newInitialValues);
}
return null;
};

@@ -66,2 +72,8 @@ FormState.prototype.componentDidMount = function () {

};
FormState.prototype.reset = function () {
var _this = this;
return new Promise(function (resolve) {
_this.setState(function (_state, props) { return createFormState(props.initialValues); }, function () { return resolve(); });
});
};
Object.defineProperty(FormState.prototype, "dirty", {

@@ -131,10 +143,13 @@ get: function () {

case 3:
errors = _b.sent();
errors = (_b.sent()) || [];
if (!this.mounted) {
return [2 /*return*/];
}
if (errors) {
if (errors.length > 0) {
this.updateRemoteErrors(errors);
this.setState({ submitting: false });
}
this.setState({ submitting: false });
else {
this.setState({ submitting: false, errors: errors });
}
return [2 /*return*/];

@@ -145,5 +160,2 @@ }

};
FormState.prototype.reset = function () {
this.setState(function (_state, props) { return createFormState(props.initialValues); });
};
FormState.prototype.fieldWithHandlers = function (field, fieldPath) {

@@ -255,6 +267,6 @@ return tslib_1.__assign({}, field, { name: fieldPath, onChange: this.updateField.bind(this, fieldPath), onBlur: this.blurField.bind(this, fieldPath) });

lodash_decorators_1.bind()
], FormState.prototype, "submit", null);
], FormState.prototype, "reset", null);
tslib_1.__decorate([
lodash_decorators_1.bind()
], FormState.prototype, "reset", null);
], FormState.prototype, "submit", null);
tslib_1.__decorate([

@@ -267,2 +279,19 @@ lodash_decorators_1.memoize(),

exports.default = FormState;
function reconcileFormState(values, oldState) {
var oldFields = oldState.fields;
var dirtyFields = new Set(oldState.dirtyFields);
var fields = utilities_1.mapObject(values, function (value, key) {
var oldField = oldFields[key];
if (value === oldField.initialValue) {
return oldField;
}
dirtyFields.delete(key);
return {
value: value,
initialValue: value,
dirty: false,
};
});
return tslib_1.__assign({}, oldState, { dirtyFields: Array.from(dirtyFields), fields: fields });
}
function createFormState(values) {

@@ -269,0 +298,0 @@ var fields = utilities_1.mapObject(values, function (value) {

@@ -20,3 +20,3 @@ # FAQ

You can do this by setting a `ref` on your `<FormState />`, and calling `validateForm` on the instance passed in.
You can do this by setting a [`ref`](https://reactjs.org/docs/refs-and-the-dom.html#creating-refs) on your `<FormState />`, and calling `validateForm` on the instance passed in.

@@ -42,4 +42,51 @@ ```typescript

## My form keeps resetting for no reason! / My form is resetting whenever I change an input!
By default `<FormState />` resets whenever any value in your `initialValues` changes. If you are basing your initial values on existing state, this lets it update when your state changes (usually this would be the result of submitting).
If this is happening on each rerender, it is likely that you are generating your `initialValues` in some way that is different each time. This can happen when you construct `Date` objects, `UUID`s, or other dynamic values inline. You can solve this by `memoize`ing your initial value creation or creating dates and other dynamic data only once outside of your component's `render` method.
```typescript
// Bad!
function MyForm() {
return (
<FormState
initialValues={
publicationDate: new Date(),
text: '',
}
>
{({fields}) => /* markup*/ }
</FormState>
);
}
// Good!
const today = new Date();
function MyForm() {
return (
<FormState
initialValues={
publicationDate: today,
text: '',
}
>
{({fields}) => /* markup*/ }
</FormState>
);
}
```
## Can I have more control over what happens when initialValues change?
You can control how `<FormState />` reacts to changes in the `initialValue` prop using `onInitialValueChanged`. This prop has three options:
- (default) `reset-all`: Reset the entire form when `initialValues` changes.
- `reset-where-changed`: Reset only the changed field objects when `initialValues` changes.
- `ignore`: Ignore changes to the `initialValues` prop. This option makes `<FormState />` behave like a [fully controlled component](https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-controlled-component). You will generally want to accompany this option with a [`key`](https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html#recommendation-fully-uncontrolled-component-with-a-key) or [`ref`](https://reactjs.org/docs/refs-and-the-dom.html#creating-refs).
## More questions
Have a question that you think should be included in our FAQ? Please help us by creating an [issue](https://github.com/Shopify/quilt/issues/new?template=ENHANCEMENT.md) or opening a pull request.
{
"name": "@shopify/react-form-state",
"version": "0.5.6",
"version": "0.6.0",
"license": "MIT",

@@ -5,0 +5,0 @@ "description": "Manage react forms tersely and type-safe with no magic.",

@@ -0,1 +1,2 @@

/* eslint-disable no-case-declarations */
import * as React from 'react';

@@ -55,2 +56,3 @@ import isEqual from 'lodash/isEqual';

validateOnSubmit?: boolean;
onInitialValuesChange?: 'reset-all' | 'reset-where-changed' | 'ignore';
children(form: FormDetails<Fields>): React.ReactNode;

@@ -72,17 +74,21 @@ }

static getDerivedStateFromProps<T>(newProps: Props<T>, oldState?: State<T>) {
const newInitialValues = newProps.initialValues;
static getDerivedStateFromProps<T>(newProps: Props<T>, oldState: State<T>) {
const {initialValues, onInitialValuesChange} = newProps;
if (oldState == null) {
return createFormState(newInitialValues);
}
switch (onInitialValuesChange) {
case 'ignore':
return null;
case 'reset-where-changed':
return reconcileFormState(initialValues, oldState);
case 'reset-all':
default:
const oldInitialValues = initialValuesFromFields(oldState.fields);
const valuesMatch = isEqual(oldInitialValues, initialValues);
const oldInitialValues = initialValuesFromFields(oldState.fields);
const shouldReinitialize = !isEqual(oldInitialValues, newInitialValues);
if (valuesMatch) {
return null;
}
if (shouldReinitialize) {
return createFormState(newInitialValues);
return createFormState(initialValues);
}
return null;
}

@@ -132,2 +138,12 @@

@bind()
public reset() {
return new Promise(resolve => {
this.setState(
(_state, props) => createFormState(props.initialValues),
() => resolve(),
);
});
}
private get dirty() {

@@ -190,3 +206,3 @@ return this.state.dirtyFields.length > 0;

const errors = await onSubmit(formData);
const errors = (await onSubmit(formData)) || [];

@@ -197,14 +213,10 @@ if (!this.mounted) {

if (errors) {
if (errors.length > 0) {
this.updateRemoteErrors(errors);
this.setState({submitting: false});
} else {
this.setState({submitting: false, errors});
}
this.setState({submitting: false});
}
@bind()
private reset() {
this.setState((_state, props) => createFormState(props.initialValues));
}
@memoize()

@@ -381,2 +393,32 @@ @bind()

function reconcileFormState<Fields>(
values: Fields,
oldState: State<Fields>,
): State<Fields> {
const {fields: oldFields} = oldState;
const dirtyFields = new Set(oldState.dirtyFields);
const fields: FieldStates<Fields> = mapObject(values, (value, key) => {
const oldField = oldFields[key];
if (value === oldField.initialValue) {
return oldField;
}
dirtyFields.delete(key);
return {
value,
initialValue: value,
dirty: false,
};
});
return {
...oldState,
dirtyFields: Array.from(dirtyFields),
fields,
};
}
function createFormState<Fields>(values: Fields): State<Fields> {

@@ -383,0 +425,0 @@ const fields: FieldStates<Fields> = mapObject(values, value => {

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc