如何从React Native中的子数组对象中返回属性?

huangapple go评论85阅读模式
英文:

How to return propertie from sub array object with react native?

问题

export const SubCategoryScreen = () => {
	const { subCategoryList } = useContext(CategoryContext);

	return (
		<SafeArea>
			<CategoryList
				data={subCategoryList[0]} // Access the array directly
				renderItem={({ item }) => {
					return (
						<Spacer position="bottom" size="large">
							<CategoryInfoCard category={item} /> {/* Pass item directly, not item.subcategories */}
						</Spacer>
					);
				}}
				keyExtractor={(item) => item.id.toString()} {/* Ensure item.id is a string */}
			/>
		</SafeArea>
	);
};
英文:

I have a react native app. And I try to show the name and image on a card.

So this is the service:

export const fetchSubCategoryData = async () =&gt; {
	try {
		const response = await fetch(&quot;http://192.168.1.68:8000/api/categories/2&quot;, {
			method: &quot;GET&quot;,
			headers: {
				Accept: &quot;application/json&quot;,
				&quot;Content-Type&quot;: &quot;application/json&quot;,
			},
		});
		if (!response.ok) {
			throw new Error(&quot;Network response was not ok&quot;);
		}

		return await response.json();
	} catch (error) {
		console.error(&quot;There was a problem with the fetch operation:&quot;, error);
		throw error;
	}
};

export const subCategoryTransform = ({ results = [] }) =&gt; {
	const mappedResults = results.map((subcategories) =&gt; {
		subcategories.images = subcategories.images;
		return {
			...subcategories,
			name: subcategories.name,
		};
	});

	return mappedResults;
};

the context:

export const CategoryContextProvider = ({ children }) =&gt; {
	const [categoryList, setCategoryList] = useState([]);
	const [subCategoryList, setSubCategoryList] = useState([]);
	const [loading, setLoading] = useState(false);
	const [error, setError] = useState(null);
	const [] = useState([]);

	const retrieveSubCategories = () =&gt; {
		setLoading(true);
		setTimeout(() =&gt; {
			fetchSubCategoryData()
				.then(subCategoryTransform)
				.then((results) =&gt; {
					setLoading(false);
					setSubCategoryList([results]);
				})
				.catch((err) =&gt; {
					setLoading(false);
					setError(err);
				});
		});
	};

	useEffect(() =&gt; {
		retrieveCategories();
	}, []);

	useEffect(() =&gt; {
		retrieveSubCategories();
	}, []);

	return (
		&lt;CategoryContext.Provider
			value={{
				categoryList,
				subCategoryList,
				loading,
				error,
			}}&gt;
			{children}
		&lt;/CategoryContext.Provider&gt;
	);
};


And the component where I want to show the name and the image:

export const SubCategoryScreen = () =&gt; {
	const { subCategoryList } = useContext(CategoryContext);

	return (
		&lt;SafeArea&gt;
			&lt;CategoryList
				data={subCategoryList}
				renderItem={({ item }) =&gt; {
					console.log(item.subcategories);
					return (
						&lt;Spacer position=&quot;bottom&quot; size=&quot;large&quot;&gt;
							&lt;CategoryInfoCard category={item.subcategories} /&gt;
						&lt;/Spacer&gt;
					);
				}}
				keyExtractor={(item) =&gt; item.subcategories}
			/&gt;
		&lt;/SafeArea&gt;
	);
};

And the api call of http://192.168.1.68:8000/api/categories/2/ looks:



HTTP 200 OK
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    &quot;id&quot;: 2,
    &quot;name&quot;: &quot;vogels&quot;,
    &quot;description&quot;: &quot;vogels&quot;,
    &quot;legislation&quot;: &quot;&quot;,
    &quot;review&quot;: &quot;&quot;,
    &quot;eaza&quot;: &quot;&quot;,
    &quot;images&quot;: &quot;http://192.168.1.68:8000/media/photos/categories/birds.png&quot;,
    &quot;animals&quot;: [],
    &quot;subcategories&quot;: [
        {
            &quot;id&quot;: 3,
            &quot;name&quot;: &quot;roofvogels&quot;,
            &quot;description&quot;: &quot;roofvogels&quot;,
            &quot;images&quot;: &quot;http://192.168.1.68:8000/media/photos/categories/predator_ETI4KPC.jpg&quot;
        },
        {
            &quot;id&quot;: 5,
            &quot;name&quot;: &quot;parkieten&quot;,
            &quot;description&quot;: &quot;parkieten&quot;,
            &quot;images&quot;: &quot;http://192.168.1.68:8000/media/photos/categories/predator_gqLXVoK.jpg&quot;
        }
    ],
    &quot;category&quot;: null
}


And then I want to show the name and images of the subcategories. So in this case:
roofvogels and parkieten.

But I get this error:

Warning: Each child in a list should have a unique &quot;key&quot; prop.%s%s See https://reactjs.org/link/warning-keys for more information.%s, 

Check the render method of `VirtualizedList`., , 
CellRenderer@http://192.168.1.68:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&amp;dev=true&amp;hot=false&amp;strict=false&amp;minify=false:82071:36
    in VirtualizedList (created by FlatList)

Question: How to return the name and images of the subcategories object?

I try this:

export const SubCategoryScreen = () =&gt; {
	const { subCategoryList } = useContext(CategoryContext);

	return (
		&lt;SafeArea&gt;
			&lt;CategoryList
				data={subCategoryList}
				renderItem={({ item }) =&gt; {
					console.log(item.subcategories);
					return (
						&lt;Spacer position=&quot;bottom&quot; size=&quot;large&quot;&gt;
							&lt;CategoryInfoCard category={item.subcategories} /&gt;
						&lt;/Spacer&gt;
					);
				}}
				keyExtractor={(item) =&gt; item.id}
			/&gt;
		&lt;/SafeArea&gt;
	);
};

But still:

Warning: Each child in a list should have a unique &quot;key&quot; prop.%s%s See https://reactjs.org/link/warning-keys for more information.%s, 

Check the render method of `VirtualizedList`., , 
CellRenderer@http://192.168.1.68:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&amp;dev=true&amp;hot=false&amp;strict=false&amp;minify=false:82071:36
    in VirtualizedList (created by FlatList)

And so this is the component when the app is first time loading. This is the main screen. And from there the user can navigate to a subcategorie card:



import { ActivityIndicator, MD2Colors } from &quot;react-native-paper&quot;;
import { FlatList, Pressable, SafeAreaView, StatusBar } from &quot;react-native&quot;;
import React, { useContext } from &quot;react&quot;;

import { CategoryContext } from &quot;../../../services/category/category.context&quot;;
import { CategoryInfoCard } from &quot;../components/category-info-card.component&quot;;
import { MD3LightTheme as DefaultTheme } from &quot;react-native-paper&quot;;
import { Search } from &quot;../components/search.component&quot;;
import { Spacer } from &quot;../../../components/spacer/spacer.component&quot;;
import { TouchableOpacity } from &quot;react-native-gesture-handler&quot;;
import styled from &quot;styled-components/native&quot;;

const SafeArea = styled(SafeAreaView)`
	flex: 1;
	${StatusBar.currentHeight &amp;&amp; `margin-top: ${StatusBar.currentHeight}px`};
`;

export const CategoryList = styled(FlatList).attrs({
	contentContainerStyle: {
		padding: 16,
	},
})``;

const Loading = styled(ActivityIndicator)`
	margin-left: -25px;
`;
const LoadingContainer = styled.View`
	position: absolute;
	top: 50%;
	left: 50%;
`;

export const CategoryScreen = ({ navigation }) =&gt; {
	const { loading, error, categoryList } = useContext(CategoryContext);
	return (
		&lt;SafeArea&gt;
			{loading &amp;&amp; (
				&lt;LoadingContainer&gt;
					&lt;ActivityIndicator animating={true} color={MD2Colors.green200} /&gt;
				&lt;/LoadingContainer&gt;
			)}
			&lt;Search /&gt;
			&lt;CategoryList
				data={categoryList}
				renderItem={({ item }) =&gt; {
					return (
						&lt;TouchableOpacity
							onPress={() =&gt; navigation.navigate(&quot;groepen&quot;, { subcategories: item.id })}&gt;
							&lt;Spacer position=&quot;bottom&quot; size=&quot;large&quot;&gt;
								&lt;CategoryInfoCard category={item} /&gt;
							&lt;/Spacer&gt;
						&lt;/TouchableOpacity&gt;
					);
				}}
				keyExtractor={(item) =&gt; item.name}
			/&gt;
		&lt;/SafeArea&gt;
	);
};

If I do this:


const retrieveSubCategories = () =&gt; {
		setLoading(true);
		setTimeout(() =&gt; {
			fetchSubCategoryData()
				//.then(subCategoryTransform)
				.then((results) =&gt; {
					setLoading(false);
					setSubCategoryList([results]);
				})
				.catch((err) =&gt; {
					setLoading(false);
					setError(err);
				});
		});
	};

Then I see in the console.log:

return (
		&lt;SafeArea&gt;
			&lt;CategoryList
				data={subCategoryList}
				renderItem={({ item }) =&gt; {
					console.log(&quot;SUBCATEGORES&quot;, item.subcategories);
					return (
						&lt;Spacer position=&quot;bottom&quot; size=&quot;large&quot;&gt;
							&lt;CategoryInfoCard category={item.subcategories} /&gt;
						&lt;/Spacer&gt;
					);
				}}
				keyExtractor={(item) =&gt; item.id}
			/&gt;
		&lt;/SafeArea&gt;
	);

SUBCATEGORES Array [
  Object {
    &quot;description&quot;: &quot;roofvogels&quot;,
    &quot;id&quot;: 3,
    &quot;images&quot;: &quot;http://192.168.1.68:8000/media/photos/categories/predator_ETI4KPC.jpg&quot;,
    &quot;name&quot;: &quot;roofvogels&quot;,
  },
  Object {
    &quot;description&quot;: &quot;parkieten&quot;,
    &quot;id&quot;: 5,
    &quot;images&quot;: &quot;http://192.168.1.68:8000/media/photos/categories/predator_gqLXVoK.jpg&quot;,
    &quot;name&quot;: &quot;parkieten&quot;,
  },
]


So this is correct.

This is the complete service:

export const fetchCategoryData = async () =&gt; {
	try {
		const response = await fetch(&quot;http://192.168.1.68:8000/api/categories/main_groups/&quot;, {
			method: &quot;GET&quot;,
			headers: {
				Accept: &quot;application/json&quot;,
				&quot;Content-Type&quot;: &quot;application/json&quot;,
			},
		});
		if (!response.ok) {
			throw new Error(&quot;Network response was not ok&quot;);
		}

		return await response.json();
	} catch (error) {
		console.error(&quot;There was a problem with the fetch operation:&quot;, error);
		throw error;
	}
};

export const fetchSubCategoryData = async () =&gt; {
	try {
		const response = await fetch(&quot;http://192.168.1.68:8000/api/categories/2&quot;, {
			method: &quot;GET&quot;,
			headers: {
				Accept: &quot;application/json&quot;,
				&quot;Content-Type&quot;: &quot;application/json&quot;,
			},
		});
		if (!response.ok) {
			throw new Error(&quot;Network response was not ok&quot;);
		}

		return await response.json();
	} catch (error) {
		console.error(&quot;There was a problem with the fetch operation:&quot;, error);
		throw error;
	}
};

export const categoryTransform = ({ results = [] }) =&gt; {
	const mappedResults = results.map((categoryList) =&gt; {
		categoryList.images = categoryList.images;
		return {
			...categoryList,
			name: categoryList.name,
		};
	});

	return mappedResults;
};

export const subCategoryTransform = ({ results = [] }) =&gt; {
	const mappedResults = results.map((subcategories) =&gt; {
		subcategories.subcategories.images = subcategories.subcategories.images;
		return {
			...subcategories,
			name: subcategories.name,
		};
	});

	return mappedResults;
};

I have one main screen with url:

> http://192.168.1.68:8000/api/categories/main_groups/

And from here you can navigate to a subcategory:

subscreen with url:

> http://192.168.1.68:8000/api/categories/2

答案1

得分: 1

你不能使用对象作为键 - 它应该是一个字符串。在你的CategoryList中,你有:

keyExtractor={(item) => item.subcategories}

尝试使用

keyExtractor={(item) => item.id}
英文:

You can't use an object as a key - it should be a string. In your CategoryList, you have

keyExtractor={(item) =&gt; item.subcategories}

Try using

keyExtractor={(item) =&gt; item.id}

huangapple
  • 本文由 发表于 2023年2月27日 02:26:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/75574146.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定