I'm building my first react native application and am having trouble fully understanding the newly introduced react hooks
Based on the user using the app (and hence an API call), I have a number of PeopleListItem
components per user. In each PeopleListItem
I want to set a state, that changes based on the users actions in the app. So user John doe could render a page with two PeopleListItem
components as follows:
<PeopleListItem>
// Somewhere in the component definition
const [attributeVale, setAttributeValue] = useState("Whatever")
</PeopleListItem>
<PeopleListItem>
// Somewhere in the component definition
const [attributeVale, setAttributeValue] = useState("Whatever")
</PeopleListItem>
This errors with:
Error: Rendered more hooks than during the previous render.
I'm a bit confused by this, as the number of PeopleListItem
is static, it's just not known up front and hence a db call needs to be made. Theoretically though, I would want to change the number of PeopleListItem
. Is it possible to use react native hooks for this use case? If not, what would be the correct approach to use states in a variable number of components?
export default function PeopleScreen() {
const [snapshot, loading, _error] = useCollectionOnce(
firebase.firestore().collection("people"),
);
if (loading) {
return (
<View style={styles.container}>
<ActivityIndicator size="large" />
</View>
);
}
return (
<View style={styles.container}>
<ScrollView>
{snapshot.docs.map((doc) => PeopleListItemComponent({ peopleDoc: doc }))}
</ScrollView>
</View>
);
}
export function PeopleListItemComponent(props: PeopleListProps) {
const [name, setName] = useState('Mary');
}, []);
useEffect(() => {
console.log("Why isn't this working?");
});
return("")
CodePudding user response:
When using hooks, you have to make sure that you call the same hooks in the same order on each render of a given component. In other words, you have to follow The Rules of Hooks.
The problem in your example is here:
<ScrollView>
{snapshot.docs.map((doc) => PeopleListItemComponent({ peopleDoc: doc }))}
</ScrollView>
You are calling PeopleListItemComponent
like a regular function. Since it contains hooks, you will get an error if you don't call PeopleListItemComponent
the same number of times on each render. It's just as if you called those hooks directly from within the map
callback.
What you really want to do is render a React element for each item in docs
. Make sure to give each element a unique key too.
<ScrollView>
{snapshot.docs.map((doc) => (
<PeopleListItemComponent
key={doc.id}
peopleDoc={doc}
/>
))}
</ScrollView>
It's perfectly OK to render components conditionally or within a loop, even if the component itself contains hooks. You just have to make sure to follow the Rules of Hooks within the body of each component.