Issue
I'm having an issue in my code, so basically I have a function called StoreScreen
where I call a search bar that I created called SearchBar and from the StoreScreen I need to access the onFocus of the searchBar, the problem is giving me is the following, first let me show you the code:
Pd. If you want to know my environment and the versions, i'll leave it all the way down
import { View, Text, TextInput, ScrollView, Button, Image } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import SliderComponent from "../Components/SliderComponents";
import ProductComponent from "../Components/ProductHorizontalComp";
import Stores from "../Data/Stores";
import { useState } from "react";
import FruitsAndVeggies from "../Data/FruitsAndVeggies";
import Akcijos from "../Data/Akcijos";
import useMiniSearch from "../Search/MiniSearchEngine";
import SearchBar from "../Components/Generic/SearchBar";
import genericStyles from "../Styles/genericStyles";
/**
*
* @returns Component with the main page where all the stores and the basic prodcuts are shown
*/
export default function StoreScreen({ navigation }) {
//variables to controll
const [isSearchFocused, setIsSearchFocused] = useState(false);
const [searchResults, setSearchResults] = useState([]);
const { results, search, autosuggest, autosuggestResults, searchIndex } =
useMiniSearch(FruitsAndVeggies, { fields: ["name"] }, { fuzzy: 0.2 });
//function to handle when the text is changed in the search bar
const handleChangeText = (text) => {
autosuggest(text);
setSearchResults(results);
};
/**
* Header that shows the title on the left and a Button on the right
* @param {string} titleText What will be shown on the title
* @param {Function} handleOnPress Function that will be called when pressed on the Button
* @param {string} buttonTitle Title of the button
* @returns
*/
const viewAllHeader = (titleText, handleOnPress, buttonTitle = "ViewAll") => {
return (
<View
style={{
flex: 1,
paddingTop: 20,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
}}
>
<Text
style={{
paddingHorizontal: 20,
fontSize: 24,
fontWeight: "700",
}}
>
{titleText}
</Text>
<Text
style={{ paddingHorizontal: 20, color: "#00da34" }}
onPress={handleOnPress}
>
View All {">"}
</Text>
</View>
);
};
const consl = () => console.log("Focused");
return (
<SafeAreaView style={{ flex: 1 }}>
<SearchBar border={true} handleOnFocus={consl} />
{/* Horizontal SrollView */}
<ScrollView>
{/* Horizontal scrollView of all the stores */}
{viewAllHeader("Stores", () =>
navigation.navigate("ViewAll", {
array: Stores,
title: "Stores",
type: 0,
})
)}
<ScrollView
style={{ marginTop: 10 }}
horizontal={true}
showsHorizontalScrollIndicator={false}
>
{Stores.map((store) => (
<SliderComponent
key={store.Id} // Make sure to provide a unique key for each SliderComponent
name={store.name}
image={store.Logo}
/>
))}
</ScrollView>
{/* Fruits and veggies */}
{viewAllHeader("Fruits and Veggies", () =>
navigation.navigate("ViewAll", {
array: FruitsAndVeggies,
title: "Fruits and vegetables",
type: 1,
})
)}
<ScrollView
style={{ marginTop: 10 }}
horizontal={true}
showsHorizontalScrollIndicator={false}
>
{FruitsAndVeggies.map((item) => (
<ProductComponent
image={item.image}
store={item.store}
name={item.name}
quantity={item.quantity}
quantityType={item.quantityType}
price={item.price}
isCardDiscounted={item.isCardDiscounted}
discountPrice={item.discountPrice}
navigation={navigation}
soldBy={item.soldBy}
key={item.id}
/>
))}
</ScrollView>
{/* Actual discounts */}
{viewAllHeader("Other discounts", () =>
navigation.navigate("ViewAll", {
array: FruitsAndVeggies,
title: "Fruits and vegetables",
type: 1,
})
)}
{/* Discount Posts */}
<ScrollView
horizontal={true}
showsHorizontalScrollIndicator={false}
style={{ marginTop: 10, paddingRight: 20 }}
>
{Akcijos.map((item) => (
<ProductComponent
key={item.id}
navigation={navigation}
image={item.image}
store={item.store}
name={item.name}
quantity={item.quantity}
price={item.price}
discountPrice={item.discountPrice}
isCardDiscounted={item.isCardDiscounted}
soldBy={item.soldBy}
/>
))}
</ScrollView>
</ScrollView>
</SafeAreaView>
);
}
and in StoreScreen I'm calling the component SearchBar which is a reusable Search bar that I created.
here's the SearchBar component:
import { View, TextInput, StyleSheet } from "react-native";
import { Ionicons } from "@expo/vector-icons";
/**
* Generic bar Component
* @param {boolean} border shows border if true
* @param {number} iconSize size of the icon of the search bar
* @param {StyleSheet.NamedStyles} addStyles add styles to the search bar
* @param {string} placeholder string that is shown in the search bar
* @param {Function} onFocus function for onFocus()
* @param {Function} onChangeText function for onChangeText()
* @param {Function} onBlur function for onBlur()
* @returns Generic SearchBar component
*/
export default function SearchBar(
border = false /** Variant option **/,
iconSize,
addStyles /** Variant option **/,
placeholder = "search" /** Variant option */,
handleOnFocus /** Default prop **/,
onChangeText,
onBlur
) {
return (
<View style={[Styles.searchbarView, addStyles]}>
<Ionicons name="search" size={20} />
<TextInput
style={{
flex: 1,
marginLeft: 5,
justifyContent: "center",
fontSize: 16,
}}
placeholder={placeholder}
onChangeText={onChangeText}
onFocus={() => {
console.log(handleOnFocus);
handleOnFocus();
}}
onBlur={onBlur}
/>
</View>
);
}
const Styles = StyleSheet.create({
searchbarView: {
height: 35,
justifyContent: "flex-start",
alignItems: "center",
flexDirection: "row",
marginTop: 30,
borderColor: "#1ACE2B",
borderWidth: 1,
borderRadius: 7,
paddingHorizontal: 10,
marginHorizontal: 20,
},
});
The problem I'm getting is when I call the SearchBar component and I try to call one of its' functions, it gives me the error of '* ERROR TypeError: handleOnFocus is not a function. (In 'handleOnFocus()', 'handleOnFocus' is undefined)' *. It seems that the handleOnFocus prop is always empty and won't be passed.
I've tried putting the function directly in the SearchBar calling
<SearchBar border={true} handleOnFocus={() => console.log("focused")} />
and I've tried doing this
<SearchBar border={true} handleOnFocus={console.log("focused")} />
and I've tried initializing the prop of handleOnFocus like this:
...
export default function SearchBar(
border = false /** Variant option **/,
iconSize,
addStyles /** Variant option **/,
placeholder = "search" /** Variant option */,
{handleOnFocus} /** Default prop **/,
onChangeText,
onBlur
) {
...
and they all give me that 'handleOnFocus' is not defined or it's not a function. And with some ifs and console.log I discovered that handleOnClose is always undefined.
The versions that I'm using::
{
"expo": {
"name": "Program",
"slug": "Program",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": [
"**/*"
],
"ios": {
"supportsTablet": true
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
}
},
"web": {
"favicon": "./assets/favicon.png"
}
}
}
Solution
It's a misconception about the way props are passed in React. Components get all of their props passed to them in a single object. Take the following example:
const MyComponent = (props) => {
return (
<Text>{JSON.stringify(props)}</Text>
);
};
const ParentComponent = () => {
return (
<MyComponent prop1='hello' prop2={42} />
);
};
On screen you should see: {"prop1":"hello","prop2":42}
, showing that all of the props are combined into that single object.
In the example in the question, you're trying to receive the props as if they were all separately passed to your component as different params.
export default function SearchBar(
border = false /** Variant option **/,
iconSize,
// ...
The way it's written, all of your props would be passed into your border
prop. The other props would all be undefined.
It's common to destructure the props object in the import line. This way, you can access your props without needing to specify props.prop1
, etc. In the example component I put above this would look like
const MyComponent = ({ prop1, prop2 }) => {
return (
<Text>{prop1}, {prop2}</Text>
);
};
The easiest edit to your component is to do the same, and destructure the props in your component arguments.
export default function SearchBar({
border = false /** Variant option **/,
iconSize,
addStyles /** Variant option **/,
placeholder = "search" /** Variant option */,
{handleOnFocus} /** Default prop **/,
onChangeText,
onBlur
}) {
Answered By - Abe
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.