简体   繁体   中英

How to solve an invalid hook call error in React Native

I'm trying to make an app using React Native and solve a problem that's been bugging me for a while. My latest attempt at solving it gave me an error: "Invalid hook call.". I'm sure my versions are matching, and I definitely only have one copy of React in the app, so apparently I'm breaking the Rules of Hooks.

I'm a relative beginner to making apps in React Native and I don't know where I'm breaking any rules with my use of hooks. As far as I can tell, I'm following the rules.

Here's the code I changed before the error threw: RowCard.js

 //normal modal visibility handler


const RowCard = (props) => {
  
  const [modalVisible, setModalVisible] = useState(false);
  setModalVisible(props.modalVisible);
 

  return(
      <TouchableHighlight
        style={styles.rowCard}
        activeOpacity={0.6}
        underlayColor={"white"}
        onPress={() => {setModalVisible(true) }}
        >

        <View style={styles.rowCard}>
          <Image source={{uri: props.image, width: 150, height: 150}} />
          <View style={styles.textBox}>
            <Text style={styles.titleText}>{props.title}</Text>
            <Text style={styles.ingredient}> Main ingredients: {props.ingredient1}, {props.ingredient2}, {props.ingredient3} </Text>
          </View>
        </View>
      </TouchableHighlight>
    )
  };

export default RowCard;

Here's the code for the other components I'm currently working on, for a broader context: DrinkPopup.js:

const [idDrink, setIdDrink] = useState(0);

const DrinkPopup = (props) => {
  
  setIdDrink(props.idDrink);

  return(
    <Modal isVisible={props.modalVisible}
    onBackdropPress={()=>{props.setModalVisible(false)}} //allows closing modal by tapping outside it or back button
    onBackButtonPress={()=>{props.setModalVisible(false)}} 
    animationIn={"slideInUp"}>  
      <View style={styles.infocard}>
          <View style={styles.titleBox}>
            <Text style={styles.header}>{idDrink}</Text>
          </View>
      </View>
    </Modal>


  )


}
});
export default DrinkPopup;

And finally, AllList.js:

export default function AllList() {
  const [isLoading, setLoading] = useState(true);
  const [drinkData,setDrinkData] = useState([]);
  const [searchValue, onChangeText] = useState(''); //needed for search
  const [reloading, setReloading] = useState(false);
  const [modalVisible, setModalVisible] = useState(false); //normal modal visibility handler
  const [idDrink, setIdDrink] = useState(0);

  useEffect (() =>  { 
    fetch('https://www.thecocktaildb.com/api/json/v1/1/search.php?s=' + searchValue)
      .then((response) => response.json())
      .then((json) => setDrinkData(json.drinks))
      .catch((error) => console.error(error))
      .finally(() => setLoading(false));
      
  },[drinkData]);
  
  return (
    
    <View style = {styles.screen}>
      <View style = {styles.searchSection}>
        <TextInput 
          placeholder="Search Drinks..."  
          style={styles.input}
          onChangeText={text => onChangeText(text)}
          value={searchValue}/>
      </View>
      <FlatList
        data={drinkData}
        keyExtractor={({ idDrink }, index) => idDrink}
        removeClippedSubviews={true}
        initialNumToRender={5}
        renderItem={({ item }) => (
          <RowCard id={item.idDrink} image={item.strDrinkThumb} title={item.strDrink} alcontent={item.strAlcoholic} 
            ingredient1={item.strIngredient1} ingredient2={item.strIngredient2} ingredient3={item.strIngredient3} setModalVisible={setModalVisible}
          />)}
        extraData={reloading}
        
      />
      <DrinkPopup modalVisible={modalVisible} setModalVisible={setModalVisible} drinkID={idDrink}/>
      
    </View>
      
  );

};
});

Where am I breaking the rules of hooks, and how do I follow them?

Many code here, but I can directly point 2 errors:

const [modalVisible, setModalVisible] = useState(false);
setModalVisible(props.modalVisible);

Do not use setModalVisible this way, but in useEffect

useEffect(() => setModalVisible(props.modalVisible), [props.modalVisible]);

And

const [idDrink, setIdDrink] = useState(0);

const DrinkPopup = (props) => {
  
  setIdDrink(props.idDrink);

  return ...
}

Why is your hook outside of your functional component?

const DrinkPopup = (props) => {
    const [idDrink, setIdDrink] = useState(0);
    useEffect(() => setIdDrink(props.idDrink), [props.idDrink]);
    ...
}

----update----

In response to your comment below regarding the too many renders, the issue is here:

    fetch('https://www.thecocktaildb.com/api/json/v1/1/search.php?s=' + searchValue)
      .then((response) => response.json())
      .then((json) => setDrinkData(json.drinks))
      .catch((error) => console.error(error))
      .finally(() => setLoading(false));
      
  },[drinkData]);

The use effect hook is watching drinkData and when it changes, calls the function inside that hook. In this case, the hook updates drinkData.

I think the error is here:

  const [modalVisible, setModalVisible] = useState(false);
  setModalVisible(props.modalVisible);

Where you are setting the modalVisible to a prop value. This can likely be moved inside of a useEffect function to be called only on mount. This is probably causing an error down the line when also using the same function here:

onBackdropPress={()=>{props.setModalVisible(false)}} //allows closing modal by tapping outside it or back button
onBackButtonPress={()=>{props.setModalVisible(false)}} 

I'd probably start here:

const [modalVisible, setModalVisible] = useState(false);
useEffect(() => {
 setModalVisible(props.modalVisible); 
}, [props.modalVisible]);

Hopefully this helps!

----update----

In response to your comment below regarding the too many renders, the issue is here:

    fetch('https://www.thecocktaildb.com/api/json/v1/1/search.php?s=' + searchValue)
      .then((response) => response.json())
      .then((json) => setDrinkData(json.drinks))
      .catch((error) => console.error(error))
      .finally(() => setLoading(false));
      
  },[drinkData]);

The use effect hook is watching drinkData and when it changes, calls the function inside that hook. In this case, the hook updates drinkData.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM