cannot navigate to same route with different params - reactjs

Is it possible in react-native to navigate through the same route with different params? When I tried it, it keeps getting me an error saying that the params are undefined. Here is my code:
function Home({ route, navigation }){
const { newText } = route.params;
return (
<View style={styles.container}>
<Text style={{fontSize:30, paddingVertical:150, fontWeight:'bold'}}>Current Balance: {JSON.stringify(newText)} PHP</Text>
<TouchableOpacity style={styles.btnLogin1} onPress={()=>navigation.navigate("AddBalance")}>
<Text style={styles.btnLogin}>Add Balance</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.btnLogin1} onPress={()=>navigation.navigate("ViewCode")}>
<Text style={styles.btnLogin}>View Code To Pay</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.btnLogin1} onPress={()=>navigation.navigate("Login")}>
<Text style={styles.btnLogin}>Logout</Text>
</TouchableOpacity>
</View>
);
}
function AddBalance({ navigation }){
const[balance, newBalance] = useState(0)
const[amount, setAmount] = useState()
function addTogether(){
const Total = balance + amount;
newBalance(Total);
MyFunction();
}
return (
<View style={styles.container}>
<Text style={{fontSize:30, paddingVertical:20, fontWeight:'bold'}}>Add Balance</Text>
<TextInput style={styles.inputBox} placeholder="Enter Amount" keyboardType={'numeric'}
onChangeText={(text) => setAmount(Number.parseInt(text))}></TextInput>
<TouchableOpacity style={styles.btnLogin1} onPress ={addTogether}>
<Text style={styles.btnLogin}>Continue</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.btnLogin1} onPress={()=>navigation.navigate("Home", {newText:
balance})}>
<Text style={styles.btnLogin}>Back</Text>
</TouchableOpacity>
</View>
);
}
function ViewCode({ navigation }){
return (
<View style={styles.container}>
<Text style={{fontSize:30, fontWeight:'bold'}}>Your Code is:</Text>
<Text style={{fontSize:20, textAlign:'center'}}>R3fGH7X95iW</Text>
<TouchableOpacity style={styles.btnLogin1} onPress={()=>navigation.navigate("Home")}>
<Text style={styles.btnLogin}>Back</Text>
</TouchableOpacity>
</View>
);
}
So the error goes when I navigate to ViewCode to pay and click the back button. How can I solve this? I also created a duplicate screen for a home to manage to go back to the home screen but when I tried to navigate to the duplicate home screen, the current balance became 0 again. What I want to do is whenever the user go back to home screen the current balance will base upon the balance the users added.

The problem is in Home, you assume route.params always there (codes below)
const { newText } = route.params;
but, when you press the back button in ViewCode, it will call navigate.navigation("Home"); without any params. (codes below)
<TouchableOpacity style={styles.btnLogin1} onPress={()=>navigation.navigate("Home")}>
<Text style={styles.btnLogin}>Back</Text>
</TouchableOpacity>
This will lead to the error that you got.
The solution is to make the param optional. You can replace this code:
const { newText } = route.params;
to
const { newText } = route.params || {newText: ""};
You can replace "" with any other text as the default newText.
For saving the value globally, I recommend using Context from React. You can read more about it here
Here is the example of a Provider component you can use:
const ExampleContext = React.createContext({
setBalance: null,
balance: "",
});
const ExampleProvider = (props) => {
const [balance, setBalance] = useState("");
return (
<ExampleContext.Provider
value={{
balance: balance,
setBalance: setBalance,
}}
>
{props.children}
</ExampleContext.Provider>
);
};
and wrap your navigator with ExampleProvider
then call setBalance from the new context like this:
function AddBalance({ navigation }){
const balanceContext = React.useContext(ExampleContext);
const[amount, setAmount] = useState()
function addTogether(){
const Total = balance + amount;
balanceContext.setBalance(Total);
MyFunction();
}
and get balance from context instead from the route.params
function Home({ route, navigation }){
const balanceContext = React.useContext(ExampleContext);
const newText = balanceContext.balance;

Related

How can I maintain the data of a child component? ReactNative

I am starting in React Native and I would like to know how I can maintain the data that is in the state of a child component.
I am making an application that generates a certain amount of tables. Inside these tables, I have a menu, and inside this menu, I have components that are in charge of the logic to be able to make the sum of the dishes that were served, and how much is the whole. But when I return to the page where my tables are, all the results of my accounts that were in each table, were deleted.
This is the component that is responsible for creating each table
export default function Cuentas() {
const { mesa, handleClick } = useContext(MesaContext);
return (
<View style={style.container}>
<View style={style.bottonContainer}>
<TouchableOpacity style={style.FAB} onPress={handleClick}>
<Text style={style.FabText}> Nueva mesa</Text>
</TouchableOpacity>
</View>
<FlatList
data={mesa}
keyExtractor={(mesa) => String(mesa.id)}
renderItem={({ item }) => <Mesa mesas={item} />}
horizontal={false}
style={style.FlatList}
showsVerticalScrollIndicator={false}
/>
</View>
);
}
This is the Component that renders a component that is in charge of rendering all the decks
export default function CuentaMesa(props) {
const {
route: { params },
navigation,
} = props;
const { mesa } = useContext(MesaContext);
return (
<View style={style.container}>
<Text style={style.TitleMesa}>{params.name}</Text>
<Platos />
</View>
);
}
This is where all the dishes are rendered
export default function Platos() {
const [platos, setPlatos] = useState(platosService);
const [total, setTotal] = useState(null);
return (
<View style={style.container}>
<View style={style.Text}>
{platos.map(plato => {
return (
<View key={plato.id} style={style.platosContainer}>
<View style={style.platosView}>
<Text style={style.platoTitle}>{plato.name}</Text>
<Text style={style.platoPrice}>${plato.price}</Text>
</View>
<View>
<Plato price={plato.price} />
</View>
</View>
);
})}
</View>
</View>
);
This is where the inputs are, which are used to do all the logic, I want the data that is here (The result of each operation that was done with the input) to be saved, so that when leaving the array, where are they the tables and when you go back in, that information is there
export default function Plato(props) {
const [input, setInput] = useState(null)
const [suma, setSuma] = useState(null)
const { price } = props
console.log(price);
console.log(input)
const sumaPrecios = () => {
setSuma(Number(input) * price)
}
return (
<View>
<Text>{price}</Text>
<Text>Suma:{suma}</Text>
<TextInput placeholder='Cantidad' style={style.input} value={input} onChangeText={setInput} />
<Button title='Total' onPress={sumaPrecios} />
</View>
)
}
Thank you very much in advance for your help.

state inside each flatlist component not being remembered

I have this flatlist which lists all the jobs,uponclick we are taken to a Job details page where you can apply to the job. On apply, the button name changes to "applied" and it is disabled. I got this part working,. however when I go back to homepage and click on the same job again, the button is clickable and still says "apply now", instead of "applied". Does this have anything to do with flatlist and navigation?
Home.js:
export default function Home(params) {
const{ navigation}=params;
...
return(
<FlatList
data={getCompanies(companies, filter)}
renderItem={({ item }) => {
return(
<TouchableOpacity onPress={()=>{ navigation.navigate('Job Details',item)}}>
<View style={styles.listingCard}>
<View style={styles.listingCardBody}>
<Text style={styles.listingCardTitle}>{item.title}</Text>
<Text style={styles.listingCardDescription}>
Here is a really simple description from {item.title} about the
role being advertized...
</Text>
</View>
</View>
</TouchableOpacity>
);
}}
keyExtractor={(item, index) => { return item.id; }}
contentContainerStyle={styles.content}
/>
);}
Job Details:
function Jobdetails({route, navigation}){
const{ title, Category, rateHourly, responsibilities,location, postedBy,id,jobOverview, jobType, startDate, endDate, latitude, longitude}= route.params;
const [ butText, setButText] = useState("Apply Now");
const [ clickable, setClickable ]= useState(false);
<TouchableOpacity disabled={ clickable } style={page.button} onPress={()=>{
//apply() works fine
apply(id).then(async (result)=>{
if(result.succeeded()){
setButText('Application Successful!');
setClickable(true);
}
});
}}>
<Text style={page.text}>{ butText }</Text>
</TouchableOpacity>
Why isn't 'clickable' value being remembered by the app?
Following up on my comment,
Create a CLickableContext.js with
import { createContext } from "react";
export const CLickableContext= createContext(null);
On a component higher up in your app, set up the provider with the usestate hook.
import { CLickableContext} from "../CLickableContext";
...
const [clickable, setClickable] = useState(false);
...
<CLickableContext.Provider value={{ clickable, setClickable }}>
<YourApp/>
</CLickableContext.Provider>
Then include the context in any compenent throughout the app
import { useContext } from "react";
import { CLickableContext} from "../CLickableContext";
//Home.js
export default function Home(params) {
const { clickable, setClickable } = useContext(CLickableContext);
const{ navigation}=params;
...
return(
<FlatList
data={getCompanies(companies, filter)}
renderItem={({ item }) => {
return(
<TouchableOpacity onPress={()=>{ navigation.navigate('Job Details',item)}}>
<View style={styles.listingCard}>
<View style={styles.listingCardBody}>
<Text style={styles.listingCardTitle}>{item.title}</Text>
<Text style={styles.listingCardDescription}>
Here is a really simple description from {item.title} about the
role being advertized...
</Text>
</View>
</View>
</TouchableOpacity>
);
}}
keyExtractor={(item, index) => { return item.id; }}
contentContainerStyle={styles.content}
/>
);}
And
//Jobdetails.js
import { useContext } from "react";
import { CLickableContext} from "../CLickableContext";
function Jobdetails({route, navigation}){
const { clickable, setClickable } = useContext(CLickableContext);
const{ title, Category, rateHourly, responsibilities,location, postedBy,id,jobOverview, jobType, startDate, endDate, latitude, longitude}= route.params;
const [ butText, setButText] = useState("Apply Now");
<TouchableOpacity disabled={ clickable } style={page.button} onPress={()=>{
//apply() works fine
apply(id).then(async (result)=>{
if(result.succeeded()){
setButText('Application Successful!');
setClickable(true);
}
});
}}>
<Text style={page.text}>{ butText }</Text>
</TouchableOpacity>

Toggling Images with a boolean state of a react functional component

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

How to close modal when navigating back to my screen?

So I have a homescreen that renders a modal component. I use some states for modal visibility. However, the problem is that when I navigate from the modal to another screen and then back to my home screen, the modal is still opened and I cannot figure out how to close it. I tried using useEffect but it does not do anything. Any tips?
This is home screen.
The AddButton component is a simple TouchableOpacity that onPress call the toggleModal function
const [isModalVisible, setIsModalVisible] = useState(false);
const toggleModal = () => {
setIsModalVisible(!isModalVisible);
};
useEffect(() => {
setIsModalVisible(false)
}, [navigation])
return (
<AddButton
title="ADD BOOK"
toggleModal={toggleModal}
/>
)
And the Modal Component is this:
const ModalComponent = ({navigation, isModalVisible, toggleModal, title, author, save, onNavigate }) => {
return (
<Modal isVisible={isModalVisible}>
<View style={styles.container}>
<Text>Modal</Text>
<View style={styles.footer}>
<TouchableOpacity onPress={toggleModal}>
<Text>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => navigation.navigate("AddBookScreen")}>
<Text>{save}</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
);
};
Modify this code
<TouchableOpacity onPress={() => navigation.navigate("AddBookScreen")}>
<Text>{save}</Text>
</TouchableOpacity>
to
<TouchableOpacity onPress={() => {
navigation.navigate("AddBookScreen")
toggleModal();
}}>
<Text>{save}</Text>
</TouchableOpacity>
extract onPress function and move it up to your page and pass it as onSaveClick callback to the modal component.
// on your page
const onSaveClick = () => {
navigation.navigate("AddBookScreen")
setIsModalVisible(false)
}
then in the modal
<TouchableOpacity onPress={onSaveClick}>
<Text>{save}</Text>
</TouchableOpacity>

Why am I getting 'Objects are not valid as a React child' error even though I am not rendering anything?

So I have a function called onHideUnderlay. It's basically just a payload builder to dispatch an action, but somehow I'm getting this error.
This is the function:
addItemToCart = () => {
let thisPayload = {};
thisPayload.cartCount=this.props.cartCount+1;
let existingContent=this.props.cartContent;
let itemToAdd = {};
itemToAdd.title=this.props.currentPickedMenuItem.title;
itemToAdd.description=this.props.currentPickedMenuItem.description;
existingContent.push(itemToAdd);
thisPayload.cartContent=existingContent;
store.dispatch(addItemToCart(thisPayload));
}
This is the JSX.
<TouchableHighlight
style={styles.cartButton}
activeOpacity={0.5}
onPress={() => {
return true;
}}
underlayColor={"forestgreen"}
onHideUnderlay={this.addItemToCart}
>
<View style={styles.cartActualButton}>
<Text style={styles.cabText}>ADD TO CART</Text>
<Icon
size={30}
style={styles.cabIcon}
name="cart-plus"
type="font-awesome"
color="white"
></Icon>
<Text style={styles.cartCount}>({this.props.cartCount})</Text>
</View>
</TouchableHighlight>;
Any help would be greatly appreciated.

Resources