Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript useState React Hook Destructuring Error (Not Returning Array?)

I'm futzing about with a simple React app for the first time, and looking to set up a simple MVC to connect with an ASP.NET backend, all being done in Visual Studio 2019 (which has caused some headaches with React). However, now that I'm trying to implement models, I'm finding that all of the suggestions for strongly typing the useState hook aren't working for me.

According to a few tutorials like this one or this one, it should be as simple as adding a type in brackets, like const [state, setState] = useState<Type>({}), since it has a generic implementation. Unfortunately, for me, this throws the error "Uncaught TypeError: Invalid attempt to destructure non-iterable instance."

This thread here suggested that switching from an array to an object by changing the [] to {}, however that simply made the two parameters I passed be undefined, so I had no state or way to update said state.

I went down the path of reading until I had a brief understanding of array destructuring, so I understand that the idea is to pass an array with two constants that will be assigned in-order the elements of the array returned by the useState hook. So, I tried manually destructuring the array, setting a constant useState[0] and useState[1] separately. When I tried this for an untyped hook, it worked as expected. When I tried this for the typed hook, I got some errors about there not being elements, and upon printing out the object, found not an array like the untyped hook, but a boolean. It seems that a typed useState is returning the value "false" instead of an array.

At this point, my best guess is that I have some dependencies that don't implement the typed useState, but I'm really hitting a stone wall on troubleshooting. Anyone have some idea on what I'm doing wrong?

Edit: The testing file I have set-up -

import React, { useState } from 'react'
import 'bootstrap/dist/css/bootstrap.min.css';
import { Product } from '../Models/Product';

const Account = () => {
    //Works as-intended
    const test = useState(5);
    //Returns false when logged
    const test2 = useState<Product>({
        "ProductID": "p#corn", "Description": "Delicious corn", "ImageLink": "https://testlink.com", "Name": "Corn", "Price": "2.99", "Category": "Food"
    });
    
    //What should work, to my understanding, however this makes the route crash when it's navigated to because of the "Inavlid attempt to destructure non-iterable instance
    const [test3, setTest] = useState<Product>({});

    function clickHandler() {
        console.log(test)
    }

    function clickHandler2() {
        console.log(test2)
    }

    return (
        <div className='wrapper'>
            <button onClick={clickHandler}>Test</button>
            <button onClick={clickHandler2}>Test2</button>
        </div>
    )
}

export default Account;

The Product model -

 export interface Product {
    ProductID: string;
    Description: string;
    ImageLink: string;
    Name: string;
    Price: string;
    Category: string;
    }
like image 342
util42 Avatar asked Sep 05 '25 03:09

util42


1 Answers

Here's a CodeSandbox with an example somewhat related to your case, which demonstrates how useState is meant to work on everyone else's machine.

As you will see from testing it and messing with the example I shared, useState with a generic type specified should be fine and dandy and behave just as you expect.

That underlines that there's something about your local machine or project environment which is special to you.

import React, { useCallback, useState } from "react";

import "./styles.css";

interface Product {
  Name: string;
  Price: number;
}

const productA = {
  Name: "Corn",
  Price: 2.99
};

const productB = {
  Name: "Frozen Orange Juice",
  Price: 10_000
};

export default function Show() {
  const [product, setProduct] = useState<Product>(productA);

  const toggleProduct = () =>
    setProduct(product === productA ? productB : productA);

  return (
    <div className="App" onClick={toggleProduct}>
      <h1>{product.Name}</h1>
      <h2>{product.Price}</h2>
    </div>
  );
}

Since you asked about how to get the best responses...

Ideally when posting try to create a problem case which other people can see failing. If you attempt to do this (e.g. using a CodeSandbox) but it works fine there, then it's a matter of working on cleaning up your own local environment until you figure out what is unique about your setup which makes code break for you but no-one else.

Ideally if you can't create it within a single page repro (sandbox), because it's something to do with your project structure, create a runnable reproduction by sharing the actual project structure and its code and configuration publically on github so people can recreate your problem by checking it out and building/running it. That way they will soon be able to track down what's distinctive about your project.

Often this process of creating a repro will help you figure out the problem anyway - e.g. you start with a vanilla create-react-app typescript skeleton from https://create-react-app.dev/docs/adding-typescript/ to populate a blank github repo and your problem case suddenly starts working there - now you have a basis for bisecting your problem by adding your project's special features to the simple repro until it breaks.

like image 164
cefn Avatar answered Sep 07 '25 21:09

cefn