Skip to content
This repository has been archived by the owner on Aug 23, 2022. It is now read-only.

Uncaught TypeError: Cannot assign to read only property of object '#<Object>' #722

Closed
dangh opened this issue Mar 27, 2017 · 7 comments
Closed

Comments

@dangh
Copy link

dangh commented Mar 27, 2017

The Problem

Cannot change field outside of initial data

Steps to Reproduce

  • Use react-redux-form 1.8.1 (after this commit 17f06a5)
  • Init form with data from redux store using actions.load() in componentWillMount
  • Initial data has field .city but not .cityNotExist
  • Focus/blur .city field, work as expected
  • Focus/blur .cityNotExist, error throwed

Expected Behavior

  • in the form onSubmit event, result must have both city and cityNotExist fields

Actual Behavior

  • only received city

Reproducible Code Example

Please check this repo https://github.com/dangh/test-rrf

screen shot 2017-03-27 at 4 58 36 pm

@peterox
Copy link
Contributor

peterox commented Mar 29, 2017

I am also seeing this problem when trying to 'load' a form

@peterox
Copy link
Contributor

peterox commented Mar 29, 2017

I've done some investigating and think I know what is causing this.

Step 1) dispatch load action
In commit 17f06a5:
The change to changeActionReducer() meant action.state is copied into $form.loadedValue.

    const formValue = action.state
      ? get(action.state, form.$form.model)
      : getFormValue(form);

    const formUpdates = {
      ...form.$form,
      value: formValue,
    };

    if (action.silent) {
      formUpdates.loadedValue = formValue;
    } else {
      formUpdates.pristine = false;
    }

action.state is modelCache[cacheId] - see forms-reducer line 91

    return {
      ...modelReducers,
      [key]: (state, action) => strategy.formReducer(model, initialFormState, {
        plugins,
        ...formOptions,
      })(state, { ...action, state: modelCache[cacheId] }),
    };

Step 2) Dispatch action for model field that doesn't exist in the loaded object EDIT
getFieldAndForm uses icepick to merge the formState

    form = i.merge(createInitialState(
      formState.$form.model,
      tempInitialState(modelPath, initialValue)), formState);

and formState contains $form which contains the reference to action.state which is a reference to modelCache[cacheId].

Icepick freezes everything.

Step 3) CacheReducer tries to update modelCache

function cacheReducer(reducer, model, cacheId) {
  return (state, action) => {
    const newState = reducer(state, action);

    modelCache[cacheId][model] = newState;

    return newState;
  };
}

This fails as modelCache[cacheId] has been frozen.

I'm don't fully (or even a little bit) understand the changes make is commit 17f06a5 so I'm not sure what the best solution is. I have forked the repo and will try and write a test for this situation so stay tuned. :-)

Cheers
Peter

@davidkpiano
Copy link
Owner

What have you found?

@peterox
Copy link
Contributor

peterox commented Mar 29, 2017

Hi David, I hit save a bit too quick

peterox added a commit to peterox/react-redux-form that referenced this issue Mar 30, 2017
peterox added a commit to peterox/react-redux-form that referenced this issue Mar 30, 2017
@peterox
Copy link
Contributor

peterox commented Mar 30, 2017

Created a pull request #727 for this issue.

peterox added a commit to peterox/react-redux-form that referenced this issue Mar 30, 2017
@BryceByDesign
Copy link

If it helps. I seem to have no issues on componentWillReceiveProps. However, setting the load action creator on componentWillMount still throws an error.

    componentWillMount() {
        const { settings, setDefault } = this.props;
        if (settings) setDefault('settings', settings);
    }

Connect

export default connect(null, {
    setDefault: (model, value) => actions.load(model, value)
})(FormComponent);

There was an error with componentWillReceiveProps as well until I set the proper model path as mentioned here

With nested form state:

const store = createStore(combineReducers({
  something: somethingReducer,
  forms: combineForms({ foo: initialFoo })
});

You now get this shape:

{
  something: ...
  forms: {
    forms: { foo: ..., $form: ... }
  }
}

So I updated my Form Component model from settings to forms.settings

<Form model="forms.settings"...

Then no issue with this the componentWillReceiveProps lifecylce method

    componentWillReceiveProps(nextProps) {
        const { settings, setDefault } = this.props;
        if (nextProps.settings) {
            setDefault('settings', nextProps.settings);
        }
    }

davidkpiano added a commit that referenced this issue Apr 4, 2017
Test and potential fix for issue #722
@davidkpiano
Copy link
Owner

I believe this was fixed with #727. Please let me know if the issue persists - I was not able to reproduce it.

ghost pushed a commit to divvito/react-redux-form that referenced this issue Nov 21, 2017
davidkpiano added a commit that referenced this issue Nov 21, 2017
ghost pushed a commit to divvito/react-redux-form that referenced this issue Nov 21, 2017
davidkpiano added a commit that referenced this issue Nov 22, 2017
Issue #722 Fixed getField missing error
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants