React TypeError: Cannot access 'title' property of undefined when using Airtable

I’m working on a React voting component where users can vote on different options. The votes get stored in an Airtable database in a table called “Votes”. But I keep getting this error: TypeError: Cannot read property 'title' of undefined. It seems like something is undefined when I try to map through my array.

voting.js

const Voting = () => {
  const [options, setOptions] = React.useState([]);
  const [isLoading, setIsLoading] = useState(true);

  const fetchData = async () => {
    const data = await base('Votes').select({}).firstPage().catch(error => console.log(error));
    const processedData = data.map((entry) => {
      const {id, fields} = entry;
      return {id, fields};
    })
    setOptions(processedData);
    setIsLoading(false);
  }

  useEffect(() => {
    fetchData();
    console.log(options)
  },[])

  return (
    <Container className="section">
      <div className="wrapper">
        <Header title="Voting" />
        <h3>Which room do you prefer?</h3>
        {isLoading ? (
          <h3>Loading data...</h3>
        ) : (
          <div>
            {options.length > 0 && options[0].title.main}
            {options.map(option => {
              console.log(options);
              const {
                id, 
                fields: { title, count },
              } = option;

              return (
                <div key={id}>
                  <div className="initial">
                    {title.toUpperCase().substring(0,2)}
                  </div>
                  <div>
                    <h4>{title}</h4>
                    <p>{count} votes</p>
                  </div>
                  <button onClick={() => console.log("vote clicked")}>
                    <FaThumbsUp />
                  </button>
                </div>
              )
            })}
          </div>
        )}
      </div>
    </Container>
  )
}

I think the issue is with how I initialize my state as an empty array and then try to access properties before the data loads. The problematic lines are:

{options.length > 0 && options[0].title.main}
{options.map(option => {
  const {
    id, 
    fields: { title, count },
  } = option;

How can I fix this undefined property error? Any help would be great.

This is a timing issue mixed with inconsistent data handling. I’ve hit similar problems with Airtable’s API - sometimes it returns records with missing fields, especially when users skip columns.

Quick fix: wrap your destructuring in try-catch or validate fields first. Don’t assume title and count exist. Use const title = option.fields?.title || 'Untitled' to prevent crashes when Airtable sends incomplete records.

Also, your options[0].title.main line is wrong - should be options[0].fields.title if you need it at all. But honestly, that line looks unnecessary for a voting component. I’d just remove it unless you specifically need to show the first option’s title separately.

The issue lies within how you access your data structure. You’re attempting to access options[0].title.main, but your data processing stores title in fields.title, not directly on the option object. Change that line to options[0].fields.title. Furthermore, the line outside the map function may cause errors if your Airtable records lack a main property in title. I recommend removing it or adding a check for the nested property. Your destructuring in the map function is correct and should work once the data loads from Airtable.

Your fetchData is probably returning null or undefined from Airtable sometimes. Add a check after the API call: if (!data || data.length === 0) return; before you process anything. Also, that options[0].title.main line won’t work - title’s in fields, not at the root level.

Your error happens because you’re accessing properties before the async data loads. The main problem is this line: {options.length > 0 && options[0].title.main} - you’re checking length but not making sure the fields object actually exists.

I’ve hit similar issues with Airtable integrations. Instead of just checking options.length > 0, verify the actual data structure exists first. Try options.length > 0 && options[0].fields before proceeding with your map logic.

Also noticed your useEffect console.log shows an empty array since setState is asynchronous. Your component tries to render before data populates. Add a check like if (!options || options.length === 0) return <div>Loading...</div> at the top of your return statement as extra protection.

I hit the same issue building a dashboard with multiple APIs. Your console.log runs before the state updates, so you’re seeing an empty array.

Your destructuring’s fine, but add safety checks. I always do this with external data:

const {
  id,
  fields: { title = '', count = 0 },
} = option;

Gives you fallbacks if fields are missing. Also, {options.length > 0 && options[0].title.main} is wrong - title’s inside fields, not on the root object.

The real issue might be your Airtable data structure. Add a console.log right after setting the processed data:

setOptions(processedData);
console.log('Processed data:', processedData);

This shows exactly what structure you’re working with. Sometimes Airtable returns records where certain fields are completely missing, not just empty.