React新手求助:TypeError: Cannot read property 'map' of undefined——嵌套数组遍历报错问题
Hey there! Let's break down why you're hitting that TypeError and fix it step by step.
First, let's look at the two main issues in your code:
1. Async setState Order Causes Intermediate Render with Empty State
In your useEffect callback, you're calling setIsLoaded(true) before updating your works state with setItems(result). Since React state updates are asynchronous, this triggers a render where isLoaded is true but works is still its initial value ([], an empty array). When you try to access works.tags on an empty array, you get undefined—and calling map() on undefined throws that error you're seeing.
2. Mismatch Between API Response Structure and Your State
Looking at your API response, it returns an object with a works array (containing a single work object). But you're setting your entire result object to the works state, so works becomes { works: [ {...} ] } instead of the single work object. That means works.tags doesn't exist—your tags are actually at works.works[0].tags.
Fixing the Issue
Let's adjust your code to fix both problems:
Step 1: Fix the State Update Order and API Data Extraction
Update your useEffect to first extract the correct work object from the API response, update the state, then mark it as loaded. Also, don't forget to add id to the dependency array (your effect should re-run when the id param changes):
useEffect(() => { let cleanupFunction = false; fetch(`http://localhost:3001/works/${id}`) .then(res => res.json()) .then( (result) => { console.log(result); // Extract the first work from the works array in the response if(!cleanupFunction) setItems(result.works[0]); setIsLoaded(true); // Move this after setting items }, (error) => { setIsLoaded(true); setError(error); } ) return () => cleanupFunction = true; }, [id])
Step 2: Adjust Initial State and Add Safeguards
Change your initial works state to null instead of an empty array, so we can explicitly check if the data is ready. Then, in your render section, add a check for works, wrap list items in a proper <ul> container, and add a key prop to each <li> (React requires this for list optimization):
const [works, setItems] = useState(null); // ... else { if (!works) { return <div className="works no-data">No work found</div>; } return ( <> <Header /> <div className="works item"> <ul> {works.tags?.map(item => ( <li key={item}>{item}</li> ))} </ul> </div> <Footer /> </> ); }
The ?. optional chain operator ensures that if works.tags is ever undefined (for example, if the API response doesn't include tags), it won't throw an error—it'll just skip rendering the list.
Why Did Direct Access Seem to Work?
When you tested {works.tags} or {works.tags[0]}, you might have been looking at the state after it had updated successfully, but the error happens in that intermediate render where works is still the initial empty array. React's state updates are batched, so that in-between render can be easy to miss!
内容的提问来源于stack exchange,提问作者MKTF

