I’m newbie to React Native for mobile development. I’m using Expo. I can’t manage a state.
I have a SearchTextBox
component, I want to set text property from the parent component, however I couldn’t manage it using useState
.
import React, { useState, useEffect } from "react";import { TouchableOpacity } from "react-native-gesture-handler";import { Ionicons } from "@expo/vector-icons";import { StyleSheet, TextInput, View } from "react-native";import defaultStyles from "../config/styles";function SearchTextBox({ searchQuery, width = "100%", onSearch, ...otherProps}) { const [query, setQuery] = useState(searchQuery); const [isClearable, setIsClearable] = useState( query != null && query.length > 0 ); const onChange = (e) => { const { text } = e.nativeEvent; setQuery(text); const length = text.length; setIsClearable(length > 0); if (length >= 2 && onSearch) onSearch(text); }; const onClear = () => { setQuery(""); setIsClearable(false); }; return (<View style={styles.container}><View style={{ width: 72, }}><Ionicons name="md-search" size={32} color={defaultStyles.colors.medium} style={styles.icon} /></View><View style={{ flex: 2, }}><TextInput autoCorrect={false} autoFocus={false} autoCapitalize="none" placeholder="Search" placeholderTextColor={defaultStyles.colors.medium} style={[defaultStyles.text, styles.text]} onChange={onChange} value={query} {...otherProps} /></View> {isClearable && (<View><TouchableOpacity onPress={onClear}><Ionicons name="md-close" size={32} color={defaultStyles.colors.medium} style={styles.icon} /></TouchableOpacity></View> )}</View> );}const styles = StyleSheet.create({ container: { backgroundColor: defaultStyles.colors.light, borderRadius: 24, flexDirection: "row", flex: 1, marginVertical: 10, }, icon: { margin: 15, paddingRight: 15, }, text: { flexGrow: 1, fontSize: 18, },});export default SearchTextBox;
And I use like this:
import React, { useState, useEffect, useRef } from "react";import { View, StyleSheet, FlatList, AsyncStorage } from "react-native";import { AdMobBanner } from "expo-ads-admob";import * as Device from "expo-device";import { ListItem, ListItemSeparator } from "../components/lists/";import Screen from "../components/Screen";import SearchTextBox from "../components/SearchTextBox";import AnimatedTextList from "../components/AnimatedTextList";import colors from "../config/colors";import searchApi from "../api/search";import useApi from "../hooks/useApi";import ads from "../config/ads";function HomeScreen() { const search = useApi(searchApi.search); const [data, setData] = useState([]); const [showRandomWords, setShowRandomWords] = useState(true); const [randomWords, setRandomWords] = useState([]); const [bannerType, setBannerType] = useState("banner"); const [initialQuery, setInitialQuery] = useState(); const getDeviceTypeAsync = async () => { const deviceType = await Device.getDeviceTypeAsync(); setBannerType( deviceType === Device.DeviceType.TABLET ? "fullBanner" : "banner" ); }; useEffect(() => { getDeviceTypeAsync; }, []); const onSearch = async (value) => { setShowRandomWords(value == null || value == undefined || value === ""); const result = await search.request(value); if (!result.ok) return; setData(result.data.data); }; useEffect(() => { const getRandomWords = async () => { try { const result = await AsyncStorage.getItem("random_words"); if (!result) return; setRandomWords(JSON.parse(result)); setShowRandomWords(true); } catch (error) { console.log(error); } }; getRandomWords(); }, []); const bannerError = (error) => { console.log("An error occured while trying to show AdMob", error); }; const onRandomWordPress = (item) => { setInitialQuery(item.title); onSearch(initialQuery); }; return (<Screen><View style={styles.searchBox}><SearchTextBox searchQuery={initialQuery} width="90%" onSearch={onSearch} /></View> {showRandomWords && (<View><AnimatedTextList items={randomWords} onPress={onRandomWordPress} /></View> )}<View style={styles.result}><FlatList data={data} keyExtractor={(word) => word.id.toString()} renderItem={({ item }) => (<ListItem title={item.word} subTitle={item.descp} /> )} ItemSeparatorComponent={ListItemSeparator} /></View><View style={styles.bottomBanner}><AdMobBanner style={styles.bottomBanner} bannerSize={bannerType} adUnitID={ads.unitID} servePersonalizedAds didFailToReceiveAdWithError={bannerError} /></View></Screen> );}const styles = StyleSheet.create({ bottomBanner: { alignContent: "center", alignItems: "center", alignSelf: "center", bottom: 0, position: "absolute", width: "100%", }, container: { flex: 1, alignItems: "center", width: "100%", flexDirection: "column", }, searchBox: { backgroundColor: colors.white, height: 100, width: "100%", padding: 10, }, result: { width: "100%", flex: 1, },});export default HomeScreen;
Here’s I bind the property
<SearchTextBox searchQuery={initialQuery} width="90%" onSearch={onSearch} />
In onRandomWordPress
I set the variable but however it doesn’t update the input’s text.
const onRandomWordPress = (item) => { setInitialQuery(item.title); onSearch(initialQuery); };
What’s the proper way to do this or what’s wrong with my implementation?
Thanks!