I have a component that renders the input field, I want to pass the data to the next page when user clicks on "next" button in the header. What is the best practice for doing so? How do I expose this into Page.navigationOptions?
Or is it best to just set up redux for these types of things?
const Page = () => {
const [desc, getDesc] = useState('');
return (
<View style={styles.inputFieldDescContainer}>
<TextInput
multiline
placeholder='Write a description...'
onChangeText={(text) => getDesc(text)}
value={desc}
/>
</View>
);
};
// How do I pass desc properties down into navigationOptions?
Page.navigationOptions = (navData) => {
return {
headerTitle: 'Page,
headerRight: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title='Next'
onPress={() => {
navData.navigation.navigate('NextPage', {data: navData});
}}
/>
</HeaderButtons>
),
headerBackTitle: null
};
};
/* NextPage.js */
const NextPage = (props) => {
console.log('enter props data', props.navigation.getParam('data'));
console.log('enter props navigation', props.navigation);
const [valueText, setValueText] = useState();
return (
<View>
<TextInput onChangeText={(text) => setValueText(text)} value={valueText}/>
<TouchableOpacity><Text>Create your workout</Text></TouchableOpacity>
</View>
);
;}
Sharing state and props between component and options is possible in React Navigation 5 https://blog.expo.io/announcing-react-navigation-5-0-bd9e5d45569e
In React Navigation 4, you can use params to store the value to be able to share it:
const Page = ({ navigation }) => {
const desc = navigation.getParam('description', '');
return (
<View style={styles.inputFieldDescContainer}>
<TextInput
multiline
placeholder='Write a description...'
onChangeText={(text) => navigation.setParams({ description: text )}
value={desc}
/>
</View>
);
}
Related
I have a react function component, that I do not want to convert to a class component. I want it to have the functionality so that when it is pressed, the image is changed. However, currently, it is only showing one of the images (checked.png). What am I doing wrong?
const SignUpScreen = () => {
const [check, setCheck] = useState(false);
const changeImage = () => {
setCheck((prevCheck) => !prevCheck);
};
return (
<View>
<Text>
Select the box to change the image
</Text>
<TouchableOpacity onPress={() => changeImage()}>
<Image
source={
{ check } === true
? require("../img/unchecked.png")
: require("../img/checked.png")
}
/>
</TouchableOpacity>
</View>
);
};
export default SignUpScreen;
Remove {} around the check
const SignUpScreen = () => {
const [check, setCheck] = useState(false);
const changeImage = () => {
setCheck((prevCheck) => !prevCheck);
};
return (
<View>
<Text>
Select the box to change the image
</Text>
<TouchableOpacity onPress={() => changeImage()}>
<Image
source={
check === true
? require("../img/unchecked.png")
: require("../img/checked.png")
}
/>
</TouchableOpacity>
</View>
);
};
export default SignUpScreen;
Otherwise it is an object created everytime
I've two functional components CustomerDetails and other is MainDetails i want the state value of textInputName and textInputId, so i pass props in MainDetails component
But im getting error :
const CustomerDetails = ({ navigation }) => {
const [textInputName, setTextInputName] = React.useState("");
const [textInputId, setTextInputId] = React.useState("");
return (
<View style={styles.container}>
<NavigationBar
componentCenter = { () => <ComponentCenter /> }
navigationBarStyle= {{ backgroundColor:'#0095ff87' }}
statusBarStyle = {{ barStyle: 'light-content', backgroundColor: '#215e79' }}
/>
<Text style = { styles.heading }>Customer Details</Text>
{ error ?
<Text style={{color: 'red', textAlign:'center'}}>{error}
</Text> : null
}
<TextInput
style = {styles.input}
placeholder ="Enter Doctor Id"
onChangeText ={
(value) => setTextInputId(value)
}
value = { textInputId }
underlineColorAndroid="transparent"
/>
<TextInput
style = {styles.input}
placeholder = "Enter Name"
onChangeText = {
(value) => setTextInputName(value)
}
value = { textInputName }
underlineColorAndroid="transparent"
/>
<TextInput
style = {styles.input}
placeholder = "Enter Email(optional)"
underlineColorAndroid="transparent"
/>
<View style={{ marginTop: 15 }}>
<TouchableOpacity
style = {styles.submitButton}
onPress={() => {
if (textInputId.trim() === "") {
setError("Id Required.")
}
else if( textInputName.trim() === ""){
setError("Name Required.")
}
else{
navigation.navigate('MainDetails')}}
}>
<Text style = {styles.submitButtonText}> Connect </Text>
</TouchableOpacity>
</View>
</View>
)}
const MainDetails = ({ navigation, props }) => {
var idData = props.textInputId
var nameData = props.textInputName
return (
)}
function Customer() {
return (
<NavigationContainer>
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="CustomerDetails" component={CustomerDetails} />
<Stack.Screen name="MainDetails" component={MainDetails} />
</Stack.Navigator>
</NavigationContainer>
);
}
You need to pass params to MainDetails via route (assuming you're using React Navigation): https://reactnavigation.org/docs/params/
So your code should look like:
const CustomerDetails = ({ navigation }) => {
const [textInputName, setTextInputName] = React.useState("");
const [textInputId, setTextInputId] = React.useState("");
...
navigation.navigate('MainDetails', { textInputId, textInputName })
...
const MainDetails = ({ navigation, route }) => {
const { textInputId, textInputName } = route.params;
return (
)
}
i'm trying to access the code and name value from within my child component which is a flatlist and access the select data in the parent component:
My flatList is as follows & it house a child component on which it will render items to. But however i get undefind or maybe i've used the wrong approach
const CustomerView = ({ code, name, email, balance, buttonPress }: any) => {
return (
<View style={styles.body}>
<TouchableOpacity onPress={buttonPress}>
<Text>Code: {code}</Text>
<Text>Name: {name}</Text>
<Text>E-Mail: {email}</Text>
<Text>Balance: {balance}</Text>
</TouchableOpacity>
</View>
);
};
And below is my flatList component which will render the above componet when data gets passed through
const CustomerFlatList = ({
customerData,
onPressSelectCustomer,
}: any) => {
return (
<View style={styles.body}>
<FlatList
data={customerData}
keyExtractor={(customerData) => customerData.code.toString()}
//I need to access code and name in the parent component
renderItem={({ item: { code, name, email, balance } }) => {
return (
<View>
<CustomerView
code={code}
name={name}
email={email}
balance={balance}
buttonPress={onPressSelectCustomer}
/>
</View>
);
}}
/>
</View>
);
};
And my home component which is supposed to get code, name passed through in order to trigger an event with there data being passed through
const SelectCustomerScreen = ({navigation}) => {
const customers = useSelector((state: RootStateOrAny) => state.customers);
const getCustomerDetails = (code, name) => {
//navigation.navigate("orderScreen");
console.log(code, name)
}
return (
<View style={{ flex: 1 }}>
<CustomerFlatList
customerData={customers}
doc_type={documentType}
invoiceScreen={invoiceScreen}
quotationScreen={quotationScreen}
onPressSelectCustomer={getCustomerDetails}
/>
</View>
);
};
I am working on a react-native contact app with realtime search functionality. I have a problem with the contact List re-rendering on every keypress. is there a way I can optimize the search function where I can avoid the unnecessary re-renders on contacts Flatlist. Thanks, in advance
here is my contact component:
const Contacts = () => {
const [contact, setContact] = useState({});
useEffect(() => {...read contacts and then save it to contact and inMemoryContact state});
const renderItem = ({ item }) => <RenderContacts item={item} />;
const renderList = () => {
return (
<FlatList
keyboardShouldPersistTaps="handled"
data={contact}
keyExtractor={(item, index) => index.toString()}
renderItem={renderItem}
/>
);
};
return (
<View>
<Text style={Styles.textStyle}>All Contacts</Text>
{renderList()}
</View>
);
};
here is my search component:
const SearchBar = ({ updateContactState }) => {
const { inMemoryContact } = useSelector(state => state.contactReducer);
const searchContacts = value => {
const filteredContact = inMemoryContact.filter(contactToFilter => {
const contactLowerCase = `${contactToFilter.firstName} ${contactToFilter.lastName}`.toLowerCase();
const searchTerm = value.toLowerCase();
return contactLowerCase.indexOf(searchTerm) > -1;
});
updateContactState(filteredContact);
};
return (
<View style={Styles.SectionStyle}>
<MaterialIcons style={Styles.iconStyle} name="search" size={28} />
<TextInput
placeholder="Search Contact"
autoCapitalize="none"
autoCorrect={false}
onChangeText={content => {
searchContacts(content);
}}
/>
</View>
);
};
here is my renderContact component which keeps re-rendering:
const RenderContacts = ({ item }) => {
return item.phoneNumbers.map(element => (
<TouchableOpacity ...>
... list of contacts
</TouchableOpacity>
));
)
}
Your Problem Statement
"contact List re-rendering on every keypress"
Proposed Solution
Use debounce to delay the call. Here is a detailed article on what debounce does. Debounce will delay processing your input until a certain delay period. This will prevent the extra re-renders that can occur while a user is quickly typing in the search bar.
debounce function is readily available in most utils library including lodash.
Two solutions:
Use RenderContact as a function not JSX element
Bring it outside the scope of your main function
Let me know which one works for you.
I want to display something in my react component when user clicks into a text input (something similar to Instagram's search, where if you click on their input field, a search component suggestion shows up.
const SearchScreen = props => {
const renderSearch = () => {
return (
<>
// need to display the search suggestion
</>
)
}
return (
<>
<TextInput
placeholder="Search"
onChangeText={text => handleChange(text)}
value={searchText}
onFocus={() => renderSearch()} // based on focus, then render component
/>
<View>
// how do I render here?
// this will render on load, but need to render onFocus
{renderSearch}
</View>
</>
);
};
You can apply a similar pattern than stackoverflow.com/a/34091564/1839692.
For instance you can try something like :
const SearchScreen = props => {
const [searchFocus, setSearchFocus] = useState(false)
const renderSearch = () => {
return (
<>
// need to display the search suggestion
</>
)
}
return (
<>
<TextInput
placeholder="Search"
onChangeText={text => handleChange(text)}
value={searchText}
onFocus={() => setSearchFocus(true)}
onBlur={() => setSearchFocus(false)}
/>
{ searchFocus
? <View>
{renderSearch}
</View>
: <View>
// Add here the code to display when not searching
</View>
}
</>
);
};