We have been struggling w/ this for a while now and following some of the related issues. I'm not sure if our problem is directly related to these others or not (using release 4.1.6
):
To summarize, we are finding that values are not being initialized until the second render cycle for our reduxForm-ed components. Example being that none of the following properties would be initialized until the first call of componentWillReceiveProps
(i.e. the 2nd render):
props.fields.someField.value
props.values.someField
Although, the following properties are initialized (even for the 1st render cycle) according to initialValues
props.fields.someField.defaultValue
props.fields.someField.initialValue
My question would be, is what I've described above the _expected_ behavior from redux-form
? This causes issues for us where children component who depend on valid props being passed down to them receive undefined
on the 1st render cycle and we can not rely on the "values" being reliably initialized.
We have resorted to something similar to
render() {
if (typeof values.someField === 'undefined') {
return null;
}
// ...
}
but then we can not rely on componentDidMount, etc...
I will make an effort to circle back and try and clarify this issue. I just want to get this out there for possible discussion. Any feedback/advice is much appreciated!
Here is some mostly-valid code below to illustrate the issue we have been experiencing
const SomeForm = React.createClass({
componentWillMount() {
const {values} = this.props;
if (typeof values.someString === 'undefined') {
// All values = undefined
// props.fields.someString.defaultValue is set as expected
// props.fields.someString.initialValue is set as expected
debugger;
} else {
debugger;
}
},
componentDidMount() {
const {values} = this.props;
if (typeof values.someString === 'undefined') {
// All values = undefined
// props.fields.someString.defaultValue is set as expected
// props.fields.someString.initialValue is set as expected
debugger;
} else {
debugger;
}
},
componentWillReceiveProps(newProps) {
const {values} = newProps;
if (typeof values.someString === 'undefined') {
debugger;
} else {
// Values initialized on 1st call (2nd render)
debugger;
}
},
render() {
const {
fields: {someString, someArray, someObject},
} = this.props;
return (
<div>
<ComponentUsesSomeString
value={someString.value}
onChange={someString.onChange}
/>
<ComponentUsesSomeArray
value={someArray.value}
onChange={someArray.onChange}
/>
<ComponentUsesSomeObject
value={someObject.value}
onChange={someObject.onChange}
/>
</div>
)
}
});
const ReduxFormedSomeForm = reduxForm(
{name: 'SomeForm', fields: ['someString', 'someArray', 'someObject']},
(state) => {
return {
initialValues: {
someString: 'Some String',
someArray: ['some', 'array'],
someObject: {a: 'some', b: 'object'},
},
};
}
)(SomeForm);
const App = React.createClass({
render() {
return (
<div>
<ReduxFormedSomeForm />
</div>
)
}
})
Excellent description. :+1: I understood what you meant before I even got to the code.
Yes, this is a bizarre inconsistency with the library that should be remedied. The problem is that it is using the values from the redux state, which are not yet set until the the INITIALIZE
action gets dispatched on componentWillMount()
, so it doesn't get them until the second render. What needs to happen is that redux-form
needs to be smart enough to go ahead and merge in any initialValues
as though they were the values from the redux state on the first render.
I think I know how to fix this, but I can't get to it today.
Is there any practical solution to this ?
I went for this in my form Component:
componentDidMount() {
// handle server side rendering, that bring a form that is NOT initialized
if (! this.props.initialized) {
this.props.dispatch(reset('project'));
}
}
@erikras so... if I understand correctly, the problem is caused by following reason:
As i see, we need move initialize from reducer to component, so we will have all fields and form with initial values in component from the very beginning. Then we can define shouldComponentUpdate that will prevent second render if there was nothing changed in fields or form
guys, nobody cares? why?
I care, but I am currently focusing my efforts on the next version, which will take this and all the other unresolved bugs of v4
into account. It's maybe a month or two away from release. I have not taken the time to examine your analysis in depth, but it sounds like you have analyzed the problem well. If you would like to submit a PR that makes the test I wrote (linked above) pass and doesn't break any of the other tests, I'd be happy to accept it into v4
.
I am currently seeing this double render as well, which is also affecting the validate function (getting called the 1st time without any values from initialValues, even though they are available).
Anyway - I think @sars has properly identified the issue, now it's time to conceive a solution.
+1
+1
+1
Also causes some tests to fail / be run twice.
Just to let anybody know that stumbles across this, it looks like this issue was specifically solved in the 5.0.0 release
The
value
prop of your fields will never beundefined
[...]
I have yet to fully confirm this (to update our usages to 5.x), but if that is the case this issue might be appropriately closed (unless a 4.x patch is really needed/in demand).
In my case v5 only sets the value to ""
, not to initialValue
like I expected.
Hey guys. Just wanted to let you know v6.0.0-alpha
has been released!
@silvenon it seems that the change from "uninitialized being `undefined" to "uninitialized being an empty string" might make things worse (for my use cases at least). If you see my examples above (issue description), that is how we are guarding against attempting to render w/ uninitialized values. Hmmm....
FYI I am diving into this now to address throughout our project(s) at work (we ended up having to guard against this on every usage of redux-form
throughout :sweat_smile:...) I'll be sure to update if I land on any sensible workaround or come up with a possible patch to submit. I do have a few in mind that I'll start playing with.
It seems that I may be better off sticking w/ v4.x for now considering the "empty string" issue @silvenon described here
@erikthedeveloper I downgraded as well.
Hey all! I just submitted https://github.com/erikras/redux-form/pull/843 as a fix for this. As far as I understand things, it should pretty well cover this issue. Thanks @sars for laying out the flow of things, that helped me dive in a lot easier ๐
cc @silvenon @Guibod @shilpan
@erikthedeveloper Waiting for a merge from @erikras
I case anybody is looking for a temporary fix before https://github.com/erikras/redux-form/pull/843 or others are accepted/merged, this is loosely what I've landed on for the moment so that I can sweep through and remove all my temporary hacks/guards throughout my components. This at least opens up a reliable data flow so that values[field]
and fields[field].value
are reliably set (for use within that 1st pesky render cycle and components' lifecycle methods).
// SomeFormComponent.js
import { makeFormSafe } from '../../makeFormSafe';
export const MyForm = React.createClass({/* */});
// ...
export const MyFormConnected = reduxForm(
/*...*/
)(makeFormSafe(MyForm));
// makeFormSafe.js
import { createElement } from 'react';
import _ from 'lodash';
const fieldToValue = ({value, initialValue}) => typeof value !== 'undefined'
? value
: initialValue;
const makeFieldsSafe = (fields) => _.mapValues(fields,
(field) => typeof field.value !== 'undefined'
? field
: {...field, value: fieldToValue(field)}
);
const makeValuesSafe = (values, safeFields) => _.mapValues(values,
(value, fieldName) => typeof value !== 'undefined'
? value
: safeFields[fieldName].value
);
/**
* "Safely" wrap up a FormComponent before passing it to reduxForm
* This basically ensures that field.value and values[field] are reliably available...
* Pending redux-form patch. See {@link https://github.com/erikras/redux-form/pull/843}
* @param {Component} component
* @return {Component}
*/
export function makeFormSafe(component) {
const ReduxFormSafetyWrapper = ({fields, values, ...otherProps}) => {
const safeFields = makeFieldsSafe(fields);
return createElement(component, {
...otherProps,
fields: safeFields,
values: makeValuesSafe(values, safeFields),
});
};
return ReduxFormSafetyWrapper;
}
@erikras Can you please accept the merge? The issue is still relevant and needs an urgent fix
I apologize, @NSLS and @erikthedeveloper, I totally missed seeing that PR.
Thanks a ton @erikras!
Published as v5.1.4
. ๐ Cheers, @sars and @erikthedeveloper!
@erikthedeveloper Can you please look at this test that I wrote to demonstrate the bug for this issue? It's still not passing with your PR. Either the test is wrong or the bug is not really fixed.
@erikras I've been looking into this. I'm not quite familiar with all of the inner workings here. If I follow this all correctly, it seems that the point of entry for the problem is somewhere underneath ReduxForm.constructor
assigning this.fields
via readFields(/* ... */)
, likely within or under readField
about in this hunk
Either that or initializeState
.
Also, I have been unable to locate where field.defaultValue
is being set... only where it is being tested for.
I'm still digging in so I'll be sure to post what I come up with.
@erikras After digging around for what amounted to my full morning, I have yet to come up with a sensible solution for this. I'm going to have to call it quits for the moment... I'll see if I can circle back sometime this week.
The key components I found myself digging around in were
getValues.js
updateField.js
readFields.js
It may be related to the change in behavior from 4.x to 5.x described [https://github.com/erikras/redux-form/issues/621#issuecomment-213152226] there seems to be some conflict/duplication surrounding where we "fallback/default" certain properties.
@erikthedeveloper Okay, no worries. No doubt the library is better with your PR than without it, but I don't think the dragon is quite dead yet.
After a few hours digging. I think the key point is here and here. In readField.js#L119
field.value
is assigned by the initial value that is what we expected, but in updateField.js#L9
, because at very first, form state is not created yet, so formFieldValue
will always be ''
and override the initial value at updateField.js#L13
.
I have an issue with this and nested fields. If I try to 'clear' the form by changing the state of my store, not all fields are set to the right value. Let's say I have the following object in the store:
state.myObject = {
"name": "test",
"properties": [
{
"name": "first"
},
{
"name": "second"
}
}
and the following form initialization:
MyForm = reduxForm({
form: 'myForm',
fields: [
'name',
'fields[].name'
]
},
state => ({
initialValues: state.myObject
}))(MyForm);
Now if somewhere I dispatch an action that reinitialize state.Object
to {}
or undefined
, the form state will be in a weird state where fields
contains 2 empty object. I would expect it to fallback to the initial state instead (where fields
is empty).
I now use
import { destroy } from 'redux-form';
...
dispatch(destroy('myForm'));
inside my action that reinitialize state.Object
and it seems to do the trick. Not quite sure if this is the way to go because now my reducer has a dependency on the redux-form's one and needs to know the name of the form.
Fix published as v5.2.5
.
I'm still getting uninitialized values in validate
hook with v5.2.5
@yesmeck ?
๐ข Forgot the validate
here, conceiving a solution.
Very confused - @erikras @yesmeck I am using v5.2.5
but I seem to have the problem described in the initial post. Perhaps @rpominov has the same. Is a solution coming? Including checks for undefined
in validation where I shouldn't need them is getting tedious.
had this problem with a version 3.X.X from react-redux-hot-example boilerplate, just updated to latest version and errors are GONE.
thx ;-)
I seem to be experiencing this also. Digging around it seems like the overwrite from initial values is occurring at this line:
https://github.com/erikras/redux-form/blob/master/src/updateField.js#L10
I'm not sure what the value of formField
is supposed to be when updateField
is called... but it appears to be an empty object which causes my value to always default to ""
.
I may have the opportunity to dive into this at a later point.
Update Apparently the form has not been initialized yet. Maybe the right approach is to not call updateField
if the the form has not been initialized yet. Thoughts?
Final Update I apologize, this was fixed in the v5.2.5
. Not sure how I missed that :/
Thanks you guys!
@erikras I still see this problem in v5.2.5 when using this.props.values
. I saw in the debugger in the redux-form HOC that this.fields._meta.values
has keys for the fields, but the values are all undefined
in the first render, even though initialValues
are correct. Is this expected behavior?
Seeing an issue with v5.2.5 as well. validate
is being called with undefined
/null
when the form mounts. When I handle that with an if statement the form mounts successfully, but any future calls of validate
are not causing the form to re-render. Strangely, everything works successfully when using react-hot
loader locally. It is just in the production deployment that I am having any issues. Sorry if that is vague/confusing.
Update
Found a workaround. Instead of relying on values
passed in to my validate function, I am using props
which is passed in as a second parameter. props
is has the correct values passed through from src/readFields.js.
still seeing this in v6.0.0.rc3
yes this problem also exists in v6.0.0.rc3
In v6.0.0.rc4 there is the boolean enableReinitialize
form config property, that worked for me
Correct take a look at enableReinitialize
Also, be sure to not dispaly your form before you actually have initial values...
e.g.
// ...
render() {
const { post } = this.props;
return (
<div className="redux-form">
{post && <UpdatePostForm initialValues={post} />}
</div>
);
}
// ...
Does anyone still see this issue? Or is it only me and i'm missing something?
I have a form and using enableReinitialize with initialValues and a validation of required fields.
Once the INITIALIZE is dispatched, the validate function gets a values with an empty object.
After all the fields are registered, a second call is made to the validate function (not sure how and why..?) but it does not update the form state so there are still sync errors present.
The issue that i see is after all this initialisation, if i go to the form, click on a field and then on something else, the error is shown. Even though the value there is actually valid
I'm having an issue as well which is caused by this, I believe.
In my form, i define initialValues:
FindOrdersForm = reduxForm({
form: FIND_ORDER_FORM,
initialValues: {
startDate: moment().subtract(1, 'months'),
endDate: moment()
}
})(FindOrdersForm);
In a parent component that renders this form, I need to access these initial values in componentDidMount
. I've tried doing it using getFormValues
, but the values are undefined. So no initial values present.
Any ideas?
I'm still having this issue in 6.0.5.
I'm having a similar issue with the second render cycle. I've got an outstanding SO question here outlining my issue: http://stackoverflow.com/questions/40565652/display-server-message-on-initial-redux-form-load I'm simply trying to initialise the form submit to subsequently display a react-toaster alert on the first cycle of loading a registration form. It works great if I click a second time on my submit button. (Using redux-form 6.1.1)
I'm testing for the existence of the registering user then I pop up a notification from the server if the user already exists. Chrome auto-fills the email/password fields in my form and when I click 'Register' (the first time), nothing happens until I click submit a second time. I've tried all sorts of combinations to try and get the props set properly on initial load from the server-side user check, but no luck yet.
@erikras any news on this?
same problem here @erikras
Thanks seems like enableReinitialize does the job
@erikthedeveloper, @erikras enableReinitalize does the job, but the validate is not working because it is getting undefined/null and here is the error what I am getting with the validate which I am passing to the redux-form:
If I remove the validate from the redux-form, everything works perfectly.
The code for the editTeam is here: https://gist.github.com/reznord/eb0e50539dc72484b7d446f7b8141280
It would be great if I can get a solution for this, on how to use the redux-form validation here.
Thanks in advance.
Hi Anup:
If your code is available somewhere on Github I could take a look at it for
you. Is your application in the public domain?
Cheers,
Dave
On Mon, Dec 12, 2016 at 1:35 AM, Anup notifications@github.com wrote:
@erikthedeveloper https://github.com/erikthedeveloper, @erikras
https://github.com/erikras enableReinitalize does the job, but the
validate is not working because it is getting undefined/null and here is
the error what I am getting with the validate which I am passing to the
redux-form:
[image: screen shot 2016-12-12 at 12 02 20 pm]
https://cloud.githubusercontent.com/assets/3415488/21090028/eff69b22-c062-11e6-89b3-dee1fdd9e80f.pngIf I remove the validate from the redux-form, everything works perfectly.
The code for the editTeam is here: https://gist.github.com/reznord/
eb0e50539dc72484b7d446f7b8141280It would be great if I can get a solution for this, on how to use the
redux-form validation here.Thanks in advance.
โ
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/erikras/redux-form/issues/621#issuecomment-266353647,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ASt2yMGpE9LWldrwNoxb23Bid_bu7KOeks5rHOszgaJpZM4HTtp8
.
Ah OK, I just work on open source, sorry.
Cheers,
Dave
On Mon, Dec 12, 2016 at 11:05 AM, Anup notifications@github.com wrote:
@gridworkz https://github.com/gridworkz, the repository is private,
can't share the code. You can see my code if you are okay with helping me
out on TeamViewer.โ
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/erikras/redux-form/issues/621#issuecomment-266470484,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ASt2yIvF1eOJa_LnBX7N-K8irnTGAiyWks5rHXDZgaJpZM4HTtp8
.
It seems that the issue still persists when we set
{
enableReinitialize: true,
}
Our form has an initial value, but The form rendered twice on initial load, in the first render (componentWillMount), error is created b/c initialvalues are not filling into the props.values; but in the second render (componenetWillReceiveProps), there is values filled in and errors become empty object, then the updateSyncErrors is not called (the if statement here didn't pass)
https://github.com/erikras/redux-form/blob/master/src/reduxForm.js#L151-L152
Just a comment that this issue is still present in 6.4.3 even with enableReinitialize
and keepDirtyOnReinitialize
.
Although actually, the issue I'm mainly having is with @@redux-form/UPDATE_SYNC_ERRORS
.
See this action:
{
type: '@@redux-form/INITIALIZE',
meta: {
form: 'myFormName',
keepDirty: true
},
payload: {
contactName: 'notempty',
contactSurname: 'notempty',
contactEmail: '[email protected]',
contactPhone: '123-456-7890'
}
is followed immediately by
{
type: '@@redux-form/UPDATE_SYNC_ERRORS',
meta: {
form: 'myFormName'
},
payload: {
syncErrors: {
contactName: 'First name?',
contactSurname: 'Last name?',
contactEmail: 'Please provide an email address.',
contactPhone: 'Please provide a phone number.'
}
}
}
This is odd, as it implies that my sync validation is not being passed the defined values, despite the fact that the initialize action clearly alters my state.form.formName.values
Yes enableReinitialize
will do the magic.
// define EditForm ...
EditForm = reduxForm({
form: 'userEditForm',
enableReinitialize: true,
})(EditForm);
I can confirm @oychao that writing code with enableReinitialize: true
like this helps:
import BigCommerceSettingsForm from 'sr/components/ecommerces/big_commerce/connection/form'
// Imported a component stateless function here
let ConnectedBigCommerceSettingsReduxForm = reduxForm({
form: 'BigCommerceSettingsForm',
enableReinitialize: true,
})(BigCommerceSettingsForm)
ConnectedBigCommerceSettingsReduxForm = connect(
state => ({
initialValues: {
description: state.app.bigCommerceSettings.connection.description,
},
}),
)(ConnectedBigCommerceSettingsReduxForm)
enableReinitialize didn't work when I had defined redux-form version as ^6.2.0, which installed 6.6.2 version of redux form (syncErrors were present even if the form's initial values were valid). Forcing the version to 6.2.0 fixed it for me.
It works for me on current version without using enableReinitialize, but I found a strange behaviour
reduxForm({
form: 'someForm',
initialValues: { foo : 'bar' },
validate: (values) => someValidator(values, schema),
})
On validation the initial value/values is passed as Object to my validator and not as Map, so my validator crashed, expecting a Map, as described in the docs. The rest works great and comes in as Map.
So in your validator, you need to:
const { Map } = require('immutable');
values = (!Map.isMap(values)) ? new Map(values) : values ;
To force it to a Map for the initalValues :)
The "schema" thing is that we use "JSON schema" to describe our Form and our validation rules, and we validate with AJV that is a schema validator.
The issue is still there in combination with enzyme.
I thought I was reproducing this bug with 6.8.0 but after debugging more it was caused by forgetting to add the {form: formReducer}
attribute into my top level reducer. It might be worth reduce-form logging a warning if it detects that it's not properly initialized.
@gbegher I think I might be hitting the same issue (unless I'm doing something wrong).
Were you able to work around this?
EDIT : actually the answer was right before my eyes, I was using a mock store using redux-mock-store
and without reducers, so initialValues
wouldn't get populated.
Creating an actual Redux store with {form: formReducer}
worked ๐ Thanks @mdlavin !
I had this issue and figured out it was because you have to FIRST decorate with reduxForm, and then decorate with redux connect. Hope this helps someone
@flushentitypacket's solution is what worked for me. If it wasn't for that I'd still be lost...
@flushentitypacket is it possible to demonstrate it? I'm trying to figure it out!
@vctormb I don't have an example handy, but it would look something like this:
const FormDecoratedComponent = reduxForm(...)(Component)
const ConnectedAndFormDecoratedComponent = connect(...)(FormDecoratedComponent)
@flushentitypacket Humm.. I did that but it didnt work. I had to use enableReinitialize instead
I'm seeing this same problem in 7.2.0.
const ReduxExampleForm = reduxForm({
form: 'exampleForm',
enableReinitialize: true
})(ExampleForm);
const selector = formValueSelector('exampleForm');
const mapStateToProps = (state, ownProps) => ({
initialValues: {
asdf: {
xyz: false
},
credentials: ownProps.credentialsOptions[0]
},
formValues: selector(state, 'asdf.xyz')
});
formValues
are coming through as an empty object on the first render and are then populated as expected
We're seeing this issue as well using redux-form 7.2.2; this breaks things so badly that they can become disconnected from the client render cycle - i.e. svg styles not updating.
@erikras don't you think this issue needs to be reopened?
I was running into this issue and I had no idea it was being discussed. I thought I was doing something wrong. But I just stumbled on to this while looking for something else, so I'll chime in. I tried the suggestion above about connecting to reduxForm first but that didn't solve the issue. I got around it with a conditional mapStateToProps. It's probably considered sloppy but it is getting the job done:
("redux-form": "^7.2.3")
function mapStateToProps(state) {
if (state.something) {
return {
something: state.abc
initialValues: {
"abc": state.some.value,
"xyz": state.some.value,
}
}
}
else {
return {
something: state.abc
}
}
};
redux-form 7.0.4
It's very bad when your library returns empty string for registered field without value and initial value!
I am sure they would be happy about getting some help to improve it instead of a bitchy comment ;).
Ran into this issue using v7.3.0
and was banging my head on a wall for longer than I care to admit. I had enableReinitialize: true
within the _reduxForm_ options as well...
Turns out the issue was that I had another child component nested within the component tree that had its own _reduxForm_ options and because it didn't have enableReinitialize: true
. It appeared to be overwriting the functionality of the parent components _reduxForm_ options
_The fix was making sure the nested reduxForm options matched the parent component's reduxForm options_
For those of you who are still facing this issue, here is a quick hack to get around this problem.
In your form component's componentDidMount lifecycle method do the following as shown
class MyForm extends React.Component {
componentDidMount() {
this.props.initialize(this.props.initialValues); // here add this line to initialize the form
}
render() {
....
}
}
componentDidUpdate() {
if(this.props.match.params.id && !this.props.initialized)
this.props.initialize(this.props.initialValues);
}
This actually worked
I was experiencing the same symptoms with a form of mine and it seems to have been caused by having multiple forms with the same name-key. Making them unique resolved my issue and initialValues are being populated on first render :)
const formedComponent = reduxForm({
form: 'serviceLocationForm', // <- this bit was duplicated on another form
})(ServiceLocationForm);
I experienced the same issue with reduxForm 7.0.4, but it works in reduxForm 7.0.3
My node-js version is v8.9.0 fyi
Had the same problem in version 7.4.2. As in the above solutions, adding 'enableReinitialize: true' in reduxForm solved my problem.
Have the same problem in 7.4.2. Had to add enableReinitialize:true and
componentDidMount() {
this.props.initialize(this.props.initialValues);
}
I am sure they would be happy about getting some help to improve it instead of a bitchy comment ;).
Yeah, agreed, but on the other hand this is a serious bug, and it's been documented extensively in this thread, so the issue should have been reopened...
My way of dealing with this, with my own components that get wrapped with Field
, is to check if input.value
is falsy and do some something about it, e.g. return null
.
@erikras
@gustavohenke
Any chance that this gets reopened and fixed at some point?
@codewaseem 's hack was needed in order to fix this. Version: 8.1.0
@kunokdev and @codewaseem , how do I fix this using a stateless component or functional component?
Thanks @codewaseem that works well.
With functional component it can be resolved with useEffect
:
const MyForm = ({
initialize,
initialValues,
}) => {
useEffect(() => {
initialize(initialValues);
}, []);
// ...
};
Still having this problem with redux-form 8.1.1 and react-redux 7.0.3. This hack does not resolve the issue.
The problem seems to be that validate
is called before the component is rendered. Is that normal?
This hack works with redux-form 8.2.6
& react-redux 7.1.0
Is there any reason that this issue is closed?
Having initial values to not be available until 2nd render would make your code prone to null-pointer errors.
edit:
We ended up creating an HoC ๐
Most helpful comment
Yes
enableReinitialize
will do the magic.