useState setter not working in useEffect with async API call

25 replies
Last updated: Jan 28, 2026
Im creating a custom api calling input however the useState setter is not working inside useEffect async api call. Sorry for the long winded code message. Here’s my code if someone can assist:
const AsyncSelect = React.forwardRef((props, ref) => {
  const [sessions, setSessions] = useState([])

  const {
    type,         // Schema information
    value,        // Current field value
    readOnly,     // Boolean if field is not editable
	placeholder,
    markers,      // Markers including validation rules
    presence,     // Presence information for collaborative avatars
    compareValue, // Value to check for "edited" functionality
    onFocus,      // Method to handle focus state
    onBlur,       // Method to handle blur state
    onChange      // Method to handle patch events
  } = props

  // Creates a change handler for patching data
  const handleChange = React.useCallback(
    // useCallback will help with performance
    (event) => {
      const inputValue = event.currentTarget.value // get current value
      // if the value exists, set the data, if not, unset the data
      onChange(PatchEvent.from(inputValue ? set(inputValue) : unset()))
    },
    [onChange]
  )

  const inputId = useId()


	useEffect(() => {
		const getSessions = async () => {

			const data = await fetch("<https://api.call>")

			const json = await data.json()

            const tSessions = await setSessions(json.collection) //NOT WORKING!!!

    }
		getSessions()
    	.catch(console.error);
  }, [])

	return (
    <FormField
      description={type.description}  // Creates description from schema
      title={type.title}              // Creates label from schema title
      __unstable_markers={markers}    // Handles all markers including validation
      __unstable_presence={presence}  // Handles presence avatars
      compareValue={compareValue}     // Handles "edited" status
      inputId={inputId}               // Allows the label to connect to the input field
    >
      <Card padding={0}>
        <Stack>
          <Select
            id={inputId}                  // A unique ID for this input
            fontSize={2}
            padding={[3, 3, 4]}
            space={[3, 3, 4]}
            value={value}                 // Current field value
            readOnly={readOnly}           // If "readOnly" is defined make this field read only
            onFocus={onFocus}             // Handles focus events
            onBlur={onBlur}               // Handles blur events
            ref={ref}
            onChange={handleChange}       // A function to call when the input value changes
          >
            <option value={''}>---</option>
            {sessions.map((s) => ({ s.name})
          </Select>
        </Stack>
      </Card>
    </FormField>
	)
})

export default AsyncSelect
AI Update

This is a common React issue, not specifically a Sanity problem, but I can help! The issue is that setSessions is a state setter function, not an async function - it doesn't return a promise, so you shouldn't await it.

Here's the corrected code:

useEffect(() => {
  const getSessions = async () => {
    const data = await fetch("https://api.call")
    const json = await data.json()
    
    setSessions(json.collection) // Remove the await here!
  }
  
  getSessions().catch(console.error);
}, [])

Why this happens:

  • setSessions is a synchronous function that schedules a state update
  • It doesn't return a promise, so await doesn't make sense here
  • React batches state updates and applies them after your function completes

Additional improvements for your code:

  1. Fix the map syntax error - you have a syntax error in your map function:
{sessions.map((s) => (
  <option key={s.id || s.name} value={s.name}>
    {s.name}
  </option>
))}
  1. Add loading state to handle the async period:
const [sessions, setSessions] = useState([])
const [loading, setLoading] = useState(true)

useEffect(() => {
  const getSessions = async () => {
    try {
      const data = await fetch("https://api.call")
      const json = await data.json()
      setSessions(json.collection)
    } catch (error) {
      console.error(error)
    } finally {
      setLoading(false)
    }
  }
  
  getSessions()
}, [])
  1. Consider using Sanity's built-in hooks - if you're fetching Sanity data, you might want to use hooks like useLiveQuery instead of raw fetch calls for better integration with the Studio.

The main fix is removing await from setSessions - that should get your component working!

Show original thread
25 replies

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?