Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uncaught TypeError: Cannot freeze #406

Closed
Ferezoz opened this issue Jun 26, 2020 · 6 comments
Closed

Uncaught TypeError: Cannot freeze #406

Ferezoz opened this issue Jun 26, 2020 · 6 comments

Comments

@Ferezoz
Copy link

Ferezoz commented Jun 26, 2020

When using the setter function to update a value of an atom you cannot pass any object as Object.freeze(value) can throw an error in some cases.

In my case I am passing a Firebase user to update the value of an atom but I am having Uncaught TypeError: Cannot freeze error. The error happens here:

Object.freeze(value); // Make all properties read-only

Example

const userState = atom({
  key: 'userState',
  default: null
});

const [user, setUser] = useRecoilState(userState);

auth.onAuthStateChanged(fetchedUser => {
    setUser(fetchedUser);
});

Another example would be that passing something like location.ancestorOrigins will also throw the same error.

What would be the solution? Should I just take some of the properties and create a new simpler object and pass it to the setter function or somehow convert the entire user object into a freezable object?

@cybervaldez
Copy link

Since recoil is experimental, you would have more stable results by only using primitives. This is also a good practice for recoil's state persistence.

@MomchilKolev
Copy link

Having the same issue

@MomchilKolev
Copy link

MomchilKolev commented Jun 26, 2020

Apart from not using objects, is there a way to safely use objects, similar to how an array is used in the Documentation

const todoListState = atom({
  key: 'todoListState',
  default: [],
});

function TodoItemCreator() {
  const [inputValue, setInputValue] = useState('');
  const setTodoList = useSetRecoilState(todoListState);

  const addItem = () => {
    setTodoList((oldTodoList) => [
      ...oldTodoList,
      {
        id: getId(),
        text: inputValue,
        isComplete: false,
      },
    ]);
    setInputValue('');
  };

  const onChange = ({target: {value}}) => {
    setInputValue(value);
  };

  return (
    <div>
      <input type="text" value={inputValue} onChange={onChange} />
      <button onClick={addItem}>Add</button>
    </div>
  );
}

// utility for creating unique Id
let id = 0;
function getId() {
  return id++;
}

@cybervaldez
Copy link

You can use objects, but you can expect lesser errors when using primitive ones.

@drarmstr
Copy link
Contributor

Recoil freezes stored values for atoms in part to help ensure that all state changes are visible and propagated as updates through the data-flow graph. If stored values are mutated in an attempt to change state it won't be tracked or update dependencies. To help catch this, we deep freeze objects in development. However, there are situations where mutable objects may need to be used as values that don't logically represent Recoil state changes. You can use the dangerouslyAllowMutability option when constructing your atom to allow for this.

@Ferezoz
Copy link
Author

Ferezoz commented Jun 26, 2020

Thank you @cybervaldez and @drarmstr for the explanation!, I'll be trying the dangerouslyAllowMutability option.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants