facebookexperimental / Recoil

Recoil is an experimental state management library for React apps. It provides several capabilities that are difficult to achieve with React alone, while being compatible with the newest features of React.
https://recoiljs.org/
MIT License
19.5k stars 1.18k forks source link

Utilizing Atomfamily for updating the atom states and initialization #1901

Open ROZBEH opened 2 years ago

ROZBEH commented 2 years ago

First off, my apologies if this is not the right place to post this question. Following is a simple script that I am using in order to test the behavior of selectorFamily.

import {atom, selectorFamily, useRecoilState} from 'recoil'

var formState = atom({
  key: 'formState',
  default: {},
})

var formFieldState = selectorFamily({
  key: 'FormField',
  get: (field) => ({get}) => get(formState)[field],
  set: (field) => ({set, reset}, newValue) =>
    {
      if (newValue.target.value === '111'){
        reset(formState)
        return
      }
      set(formState, prevState => ({...prevState, [field]: newValue.target.value}))
    }
})

function App() {
  //////////////////////// This Line \\\\\\\\\\\\\\\\\\\\\\\\
  const [value, onChange] = useRecoilState(formFieldState('sample1'))
  return (
    <>
      <input value={value} onChange={onChange} />
    </>
  )
}

export default App

In the beginning, formState is empty since the keys are dependent on what the user selects. Now let's say we want to add sample1 to formState like const [value, onChange] = useRecoilState(formFieldState('sample1')) and then later on update it's value depending on what the user selects in the input field. The current script works fine but there is one issue, I get the following warning

Warning: A component is changing an uncontrolled input to be controlled. 
This is likely caused by the value changing from undefined to a defined value, which should not happen.
Decide between using a controlled or uncontrolled input element for the lifetime of the component. 
More info: https://reactjs.org/link/controlled-components

The warning makes sense to me because I am doing const [value, onChange] = useRecoilState(formFieldState('sample1')) without specifying the value for sample1. Does anyone know how to make this work properly without this warning? I do understand that I can simply add {sample1:{}} to the formState atom's default value during its creation but the thing is I don't know this during its creation.

koichik commented 1 year ago

I think that the cause of that warning is that the value of the control is passed undefined, so can you try pass empty string?

  get: (field) => ({get}) => get(formState)[field] ?? '',