Deconstructing state in useState in react and typescript

dko512

Is there a way to destructure a current state that has a specified shape? I have a current state in personJob but I want to able to specify which object to look at (when I click on a button that will slice that certain object and render only that data).

I get an error in TypeScript const {company, dates, duties, title} = personJob[value]; when I try to slice by that index

The error is:

Cannot destructure property 'company' of 'personJob[value]' as it is undefined.

Component:

import React, { useState, useEffect } from 'react';
import axios from 'axios';

const url = 'https://course-api.com/react-tabs-project';

interface IPerson {
    id: string;
    company: string;
    dates: string;
    duties: string[];
    title: string;
}

function App() {
    const [personJob, setPersonJob] = useState<IPerson[]>([]);
    const [value, setValue] = useState<number>(0);

    const fetchData = async () => {
        const response = await axios(url);
        setPersonJob(response.data);
    };

    useEffect(() => {
        fetchData();
    }, []);

    const { company, dates, duties, title, id } = personJob[value];

    return (
        <main>
            <h1>Jobs</h1>
            {personJob.map((job, index) => {
                return (
                    <button key={job.id} onClick={() => setValue(index)}>
                        {job.company}
                    </button>
                );
            })}
            <section>
                <article className="border-2 px-5 py-5">
                    <div key={id}>
                        <h2>{title}</h2>
                        <h3>{company}</h3>
                        <p>{dates}</p>
                        {duties.map((duty) => {
                            return <div>*** {duty}</div>;
                        })}
                        <button type="button">More Info</button>
                    </div>
                </article>
            </section>
        </main>
    );
}

export default App;

Drew Reese

Issue

On the initial render personJob is still an empty array and personJob[0] is undefined, so values can't be destructured from it.

Solution

  1. Provide a fallback object to destructure from, personJob[value] || {}.
  2. Conditionally render the section if personJob[value] is truthy and exists.

Code:

function App() {
  const [personJob, setPersonJob] = useState<IPerson[]>([]);
  const [value, setValue] = useState<number>(0);

  const fetchData = async () => {
    const response = await axios(url);
    setPersonJob(response.data);
  };

  useEffect(() => {
    fetchData();
  }, []);

  const { company, dates, duties, title, id } = personJob[value] || {}; // <-- fallback for destructuring

  return (
    <main>
      <h1>Jobs</h1>
      {personJob.map((job, index) => {
        return (
          <button key={job.id} onClick={() => setValue(index)}>
            {job.company}
          </button>
        );
      })}
      {personJob[value] && <section> // <-- conditionally render section if data available
        <article className="border-2 px-5 py-5">
          <div key={id}>
            <h2>{title}</h2>
            <h3>{company}</h3>
            <p>{dates}</p>
            {duties.map((duty) => {
              return <div>*** {duty}</div>;
            })}
            <button type="button">More Info</button>
          </div>
        </article>
      </section>}
    </main>
  );
}

Demo

Edit deconstructing-state-in-usestate-in-react-and-typescript

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related