Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.7k views
in Technique[技术] by (71.8m points)

javascript - 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?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...