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

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.

Related

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>

Accessing variables from imported component react native

Lets say I have my main component, where if the type of {data} is "textSingles" I render the TextSingle component:
const Information = (props) => {
const data = props.data
return (
<View>
<Text>Information</Text>
{data.type == "textsingle" &
<TextSingle data={data}/>
}
</View>
)}
Here is my TextSingle component":
const TextSingle = (props) => {
const [item, setItem] = useState(props.data)
const [text, setText] = useState('')
return (
<View style={[styles.card, styles.shadowProp]}>
{/* card label */}
<View style={styles.cardHeaderTextContainer}>
<Text style={styles.cardHeaderText}>{item.label}</Text>
</View>
{/* input container */}
<View style={styles.inputContainer}>
<TextInput
style={styles.textInput}
placeholder='Enter Text'
onChangeText={text => setText(text)}
autoCapitalize='none'
placeholderTextColor='#949494'
></TextInput>
</View>
</View>
)
}
Within my Information component I am rendering TextSingle. With in TexSingle I have a text input, and that value sets the "text" var.
In this case I want to send the answer to firebase.
How do I get the value of that text input in Information component?
use can use hook names useimperativehandle for use child functions in parent class. if you don't want to and you can pass function from parent here's it
in your information component
const Information = (props) => {
const data = props.data
const [text, setText] = useState('')
return (
<View>
<Text>Information</Text>
{data.type == "textsingle" &
<TextSingle data={data} onChangeText={text => setText(text)}/>
}
</View>
)}
and in your textsingle
const TextSingle = (props) => {
const [item, setItem] = useState(props.data)
return (
<View style={[styles.card, styles.shadowProp]}>
{/* card label */}
<View style={styles.cardHeaderTextContainer}>
<Text style={styles.cardHeaderText}>{item.label}</Text>
</View>
{/* input container */}
<View style={styles.inputContainer}>
<TextInput
style={styles.textInput}
placeholder='Enter Text'
onChangeText={props.onChangeText}
autoCapitalize='none'
placeholderTextColor='#949494'
></TextInput>
</View>
</View>
)
}

cannot navigate to same route with different params

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;

Checking for viewable items in a Flatlist and passing a prop if the item being rendered id matches a viewable items id

So basically what I said in the title, I am simply trying to change a prop that im passing to the component of Post if the item currently being rendered is in the viewport.
I am getting double the output like its firing twice, and its not even correct.
im comparing a key to the id (same thing) and if the 'activeVideo !== item.id' (video id's) are the same
the video should play, because i pass 'False' to the 'paused' property.
question is why am i getting double the output and why are both videos being paused when one of them clearly shouldnt>?
Need help fast, its for a school project.
Home.js
const [activeVideo, setActiveVideo] = useState(null);
const onViewRef = React.useRef((viewableItems)=> {
setActiveVideo(viewableItems.changed[0].key)
})
const viewConfigRef = React.useRef({ viewAreaCoveragePercentThreshold: 75 })
return (
<View>
<FlatList
data={posts}
showsVerticalScrollIndicator={false}
snapToInterval={Dimensions.get('window').height - 24}
snapToAlignment={'start'}
decelerationRate={'fast'}
onViewableItemsChanged={onViewRef.current}
viewabilityConfig={viewConfigRef.current}
renderItem={({item}) => <Post
post={item}
paused={activeVideo !== item.id}
/>}
/>
</View>
)}
Post.js
const Post = (props) => {
const [post, setPost] = useState(props.post);
const [paused, setPaused] = useState(props.paused);
console.log(props.paused)
const onPlayPausePress = () => {
setPaused(!paused);
};
const onPlayPausePress2 = () => {
setPaused(!paused);
};
return (
<View style={styles.container}>
<TouchableWithoutFeedback>
<Image
source={{uri: post.poster}}
style={styles.video2}
/>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback onPress={onPlayPausePress}>
<Video
source={post.postUrl}
style={styles.video}
onError={(e)=> console.log(e)}
resizeMode={'cover'}
repeat
paused={paused}
/>
</TouchableWithoutFeedback>
</View>
)}

How to access data from FlatList in to parent component to be used in a function

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>
);
};

Resources