React native pass property for async - react-native

So I got an array with a ton of fields that are bound to <Text>
Now I also have a button in here. What I want to do is onclick I want to go to a function onSubmit which also takes the value session.gameId and puts it in asyncstorage.
{this.state.sessions.map((session, index) => {
return (
<View style={styles.cardContainer}>
<Text style={styles.title} >{session.title}</Text>
<Text style={styles.text}>Organisator: {session.organizer}</Text>
<Text style={styles.text}>Hoofd Thema: {session.mainTheme}</Text>
<Text style={styles.text}>Aantal Deelnemers: {session.numberParticipants}</Text>
<Text style={styles.text}>Game Id: {session.gameId}</Text>
<TouchableOpacity style={styles.buttonContainer} >
<Text style={styles.buttonText} onPress={this.onSubmit} value={session.gameId} >
Selecteer
</Text>
</TouchableOpacity>
But I have no idea how my onsubmit can handle both an event to change page after storing the value into asyncstorage
Please help

Not sure if I'm understanding your question correctly, but if you're trying to store the value of session.gameId into AsyncStorage and then change the page, your function may look something like this:
changePage() {// functionality to navigate to another page}
/*
* have onSubmit be an async function so you use the 'await' keyword
* await forces an asynchronous line of code to wait until the operations is done before moving forward
*/
async onSubmit(gameId) {
try {
await AsyncStorage.setItem('#store:key', gameId)
} catch(error) {
// handle error
}
// however you are changing page, handle it here
// this code wont run until gameId has been stored in async storage
this.changePage()
}
You would also need to pass the gameId to the function to actually call it now:
onPress={() => this.onSubmit(session.gameId)}
Take a look at how async functions can make your life easier :)

I'm answering this assuming that when you say your onSubmit triggers "an event to change page", you mean that it navigates to another screen.
If so, you seem to be asking for something like this:
onSubmit = async gameId => {
try {
await AsyncStorage.setItem('gameId', gameId)
// Success: navigate away here
this.props.goToMyOtherScreen()
} catch {
// Handle error
}
}
To get gameId into your submit handler, you could use an inline anonymous function:
<Text
style={styles.buttonText}
onPress={() => this.onSubmit(session.gameId)}>

Related

Onclick button, state doesn't change

I'm having some troubles understanding the code.
Basically if I do this:
<Text onPress={() => console.log('123')} >123</Text>
,
and I click on the text, it logs me 123 each click.
But I'm doing a dialer app. Basically having a component Tile (representing a single number, also with secondary option (but that will be dealt with later)).
So as I'm including my (currently only single one) Tile in App.js, I want onPress event to call function that changes state of currently dialed number. So if user clicks 3 times on '1', I want the final string to be 111.
The thing is, I can see that the handleNumber() function is called once after running code and never again after clicking on the number, therefore never changing state, not logging anything.
App.js Tile implementation:
const [getNumber, setNumber] = useState();
const handleNumber = (newChar) => {
console.log(newChar);
setNumber(newChar);
}
<Tile onPress={() => handleNumber('1')} style={styles.tile} firstChar={'1'} secondChar={'✉'}/>
Tile.js:
const Tile = (props) => {
return (
<TouchableOpacity onPress={props.onPress()}>
<View>
<Text style={styles.mainChar}>{props.firstChar}</Text>
{props.secondChar ? <Text style={styles.secondChar}>{props.secondChar}</Text> : null}
</View>
</TouchableOpacity>
)
}
One more thing:
As you can see in App.js::handleNumber(),
the implementation is currently wrong, because the final number will always be just the new single number, instead of appending it to the end of string.
But if I wanted to do smth like setNumber(getNumber + newChar), it would give Maximum update depth exceeded error.
The thing here is the way that you're passing the onPress prop to TouchableOpacity. See, you're calling the props.onPress function instead of just passing it to the component, which causes the function to be executed when the component renders (or rerenders).
You should be fine just by using <TouchableOpacity onPress={props.onPress}> and then setNumber(getNumber + newChar) will be fine as well.
As a side note, you could initialize your App.js state with the '1' string that you wish to be your initial value (const [getNumber, setNumber] = useState('1')), and then the Tile component can receive getNumber directly.

Does event, onBlur, work with the React Admin useInput hook on custom field?

I have a custom field that takes JSON and dynamically prints out TextField objects.
For each TextField I have an onChange and onBlur event. The onChange is for updating the state and the onBlur is for updating the final value to be past to the API and saved.
I'm using the useInput hook to save the updated value, however, when I use onBlur it doesn't save the value.
If I only use onChange it DOES save the value, but only the first key stroke, which is why I switched to onBlur. Any ideas? Here's the code:
const DefaultField = props => {
const {
input,
} = useInput(props.record);
let parsedObj = JSON.parse(props.record.values);
const [defaultState, setDefaultState] = React.useState({
websiteLink: parsedObj.websiteLink,
menuInstructionsLink: parsedObj.menuInstructionsLink,
surveyLink: parsedObj.surveyLink
});
const handleBlur = (event) => {
parsedObj[event.target.name] = event.target.value;
props.record.values= JSON.stringify(values);
//event.target.value is the expected value but it's not persisted when I save it.
};
const handleChange = (event) => {
setDefaultState({ ...defaultState, [event.target.name]: event.target.value });
};
return (
<FormControl component="fieldset">
<FormGroup {...input} id="defaultGroup" aria-label="position">
<React.Fragment>
{ Object.keys(parsedObj).map((key) => (
<TextField
id="standard-full-width"
name={key}
label={key}
onBlur={handleBlur}
onChange={handleChange}
style={{ margin: 8, width: '500px' }}
value={defaultState[key]}
fullWidth
margin="normal"
/>
))}
</React.Fragment>
</FormGroup>
</FormControl>
)
}
I never solved it properly, but I did discover that the dataProvider was being called twice. The first time it would send the expected values, but the second time the values were set back to the original, however I noticed that the field "previousData" had the values I needed. For now I'm just making sure to use the "previousData" field. This isn't the prettiest solution, but for now it's working. Maybe it's a bug or something sinister is going on.

How do I get TouchableOpacity to call functions in a specifid order?

I am trying to set the state of a component prior to making the API call. The problem is the API call being called first. Here is what I have.
onPress={() => {
setMeal('dinner');
addToLogButtonPressed();
}}
When I press the button addToLogButtonPressed(); calls first which causes an error.
How to I call setMeal before addToLogButtonPressed?
I think you can use useEffect to do that
const [meal, setMeal] = useState('')
useEffect(() => {
addToLogButtonPressed();
}, [meal])
onPress={() => {
setMeal('dinner');
}}
I also face this problem for my previous project simply just pass meal value to your addToLogButtonPressed() and access it inside the function.
If you are not using "dinner" value anywhere else you can skip setting state it will save you one Re-render.
onPress={() => {
setMeal('dinner');
addToLogButtonPressed('dinner'); // like this
}}

Unable to receive props to dump component

I tried all possible ways to get a simple parameter on file MembershipCard.js. My Home component Home.js simply passes props to MembershipList.js where I have done minor Array operations and iterate it to prepare a list. Each item from the list is then pass on to third file MembershipCard.js. I'm getting membership object in this file and able to prepare a card list at Home page. On Home page I have to show a side line whereas I don't want this side line on other pages (which are also accessing MembershipCard.js) hence I'm trying to send a variable on which I will conditionally show side line.
But after so many try out I'm still receiving undefined
This is my React component - Home.js
render () {
return (
<Surface>
<GreetingCard profile={this.props.profile.Profile}/>
<MembershipList props={this.props}/>
</Surface>
)
}
MembershipList.js - this contain only few functions
renderMembershipCard = (membership, i, props, sideLine = true) => {
return (
<TouchableOpacity key={i} style={styles.membership} onPress={() => props.navigation.navigate('Item', { title: membership.gym_name })}>
{/* <MembershipCard {...{membership, sideLine }}/> */}
<MembershipCard {...membership} sideLine={sideLine}/>
</TouchableOpacity>
)
}
const MembershipList = (props) => {
let membership = props.props.profile.Membership
let listArray = [];
Object.keys(membership).forEach(key => listArray.push(this.renderMembershipCard(membership[key], key, props.props)));
return (
<View>
<Text style={styles.ListTitle}>Active Membership ({listArray.length})</Text>
{listArray}
</View>
);
}
MembershipCard.js - this file is part of my presentation layer. It only return a Card design.
const MembershipCard = ({membership,sideLine}) => {
console.log('sideLine', sideLine); // showing undefined
console.log('membership', membership);
return (
<Card>
<Text style={styles.gymTitleText}>{membership.name}</Text>
... JSX code
</Card>
)
Make the following changes to your code and it should work. Change props.props seems to be incorrect way of passing props. Use spread operator for passing all props to children in correct manner.
<MembershipList {...this.props}/>
const MembershipList = (props) => {
let membership = props.profile.Membership
let listArray = [];
Object.keys(membership).forEach(key => listArray.push(this.renderMembershipCard(membership[key], key, props)));
return (
<View>
<Text style={styles.ListTitle}>Active Membership ({listArray.length})</Text>
{listArray}
</View>
)}
<MembershipCard membership={membership} sideLine={sideLine}/>
I solved it using simple trik.
Instead of calling it as a component -
<MembershipCard {...membership} sideLine={sideLine}/>
call it as a simple JS function using curly braces {} -
{ MembershipCard (membership, sideLine) }
This way I can easily pass as many parameters and can easily access all those in called function.

Socket IO in React Native firing multiple events

I have been reading similar topics but I did not really get the their solutions. I have read that the cause of this behavior is if you are re-registering a new event handler. In my code I am not sure which part I am re-registering a new event handler.
SERVER
socket.on('test', function (data) {
socket.emit('test2', data);
});
CLIENT
save() {
app.io.emit('test', { hello: 'world' });
app.io.on('test2', (res)=>{
if(Object.keys(res).length > 0) {
console.log(res);
}
})
}
render() {
return (
<View style={styles.container}>
<Button title='Save' onPress={this.save}></Button>
</View>
);
}
The problem here is this, when I click the button SAVE, the number of return that the function app.io.on is throwing keeps bumping up.
Ex:
First click return once
Second click return twice
Third click returns 3x
Is there a way to prevent this from happening like it should only return once? Thanks in advance.
Anyways, I sorted it out by moving the code
app.io.on('test2', (res)=>{
if(Object.keys(res).length > 0) {
console.log(res);
}
})
on the componentDidMount() so it will called once. The event will keep on bumping up (firing multiple times) everytime this function is called which is the caused of my problem.