function gets called but no rendering is done - javascript

Is there any way to check if items are actually being rendered or not? In my code, I run a grapqhl query and then re-render some items accordingly. In my code, if there are users present, the showUsersfunction works correctly.
However, when there are no users the noUsersTextfunction is called as confirmed by console.logs but I don't see anything rendered on the screen. I thought it might be a styling issue but I also tried increasing the font or adding more items to the view - it's clearly not working. What could the issue be?
When the function noUserText is called, both isSubmitted& isNotFoundare printed as true. I am using this in my main jsx {isSubmitted && noUsersText(userData) && isNotFound}so I believe the text should show up.
const [isSubmitted, setIsSubmitted] = useState(false);
const [isNotFound, setIsNotFound] = useState(false);
const [userData, setUserData] = useState<UsersLazyQueryHookResult>('');
const noUsersText = React.useCallback(
(data: UsersLazyQueryHookResult) => {
console.log('isSubmitted', isSubmitted);
console.log('Not Found', isNotFound);
if (data) {
if (data.users.nodes.length == 0) {
return (
<View>
<Text style={styles.noUsers}>No Users Found</Text>
</View>
);}
}
},
[userData],
);
const showUsers = React.useCallback(
(data: UsersLazyQueryHookResult) => {
if (data) {
return (
<View style={styles.friends}>
{data.users.nodes.map(
(item: { firstName: string; lastName: string; id: number }) => {
const userName = item.firstName
.concat(item.lastName);
return (
<View
style={styles.item} key={item.id}>
<View style={styles.addButtonContainer}>
<Button
rounded
style={styles.addButton}
onPress={() => {
addFriend(Number(item.id));
setIsSubmitted(false);
setUserData(null);
}}>
</Button>
</View>
</View>
);
},
)}
</View>
);
}
},
[createUserRelationMutation, userData],
);
const addFriend = React.useCallback(
(id: Number) => {
createUserRelationMutation({
variables: {
..,
},
});
},
[createUserRelationMutation],
);
const getFriendId = React.useCallback(
(data: UsersLazyQueryHookResult) => {
if (data) {
if (data.users.nodes.length == 0) {
setUserData(data);
setIsNotFound(true);
//Alert.alert('User Not Found');
} else {
setUserData(data);
}
}
},
[addFriend],
);
const [loadUsers] = useUsersLazyQuery({
onCompleted: getFriendId,
onError: _onLoadUserError,
});
const handleSubmitForm = React.useCallback(
(values: FormValues, helpers: FormikHelpers<FormValues>) => {
setIsSubmitted(true);
console.log('Submitted');
loadUsers({
variables: {
where: { email: values.email },
},
});
values.email = '';
},
[loadUsers],
);
return (
<Modal
visible={showAddFriendEmailPage}
animationType="slide"
transparent={true}>
<SafeAreaView>
<View style={styles.container}>
<View style={styles.searchTopContainer}>
<View style={styles.searchTopTextContainer}>
<Text
style={styles.searchCancelDoneText}
onPress={() => {
toggleShowPage();
setIsSubmitted(false);
setUserData(null);
setIsNotFound(false);
}}>
Cancel
</Text>
<Text style={styles.searchTopMiddleText}>
Add Friend by Email
</Text>
<Text style={styles.searchCancelDoneText}>Done</Text>
</View>
<View>
<Formik
initialValues={initialValues}
onSubmit={handleSubmitForm}
validationSchema={validationSchema}>
{({ handleChange, handleBlur, handleSubmit, values }) => (
<View style={styles.searchFieldContainer}>
<View style={styles.form}>
<FieldInput
handleChange={handleChange}
handleBlur={handleBlur}
value={values.email}
placeholderText='a#example.com'
/>
</View>
<View style={styles.buttonContainer}>
<Button
rounded
style={styles.button}
onPress={handleSubmit}>
<Text style={styles.text}>Search </Text>
</Button>
</View>
</View>
)}
</Formik>
</View>
{isSubmitted && showUsers(userData)}
{isSubmitted && noUsersText(userData) && isNotFound}
</View>
</View>
</SafeAreaView>
</Modal>
);
};

React doesn't render boolean, undefined or null values. Also note that when you write conditional rendering like
{isSubmitted && noUsersText(userData) && isNotFound}
The result is returned on the first falsy value. Otherwise the last truthy value is returned
So in your case the above code return true instead of the View component
Change the above to
{isSubmitted && isNotFound && noUsersText(userData)}
and it should work

Related

React native need manual refresh ctrl+s to display data

export default class AchieveScreen extends ValidationComponent{
constructor(props) {
super(props)
this.state = {
visible: false,
filter: 1,
date: new Date(),
selected: new Date(),
loaded: false,
data: [],
feedbackText:"",
target:[],
refreshing:false,
refreshValue:1
}
}
handleUpdate = async () => {
this.setState({ loaded: false })
await this.getter()
this.forceUpdate();
};
GetData = async () => {
const {date,selected}=this.state
const data = await GetAchieve()
if (data.status == 200) {
this.setState({
data: data.data,
target:data.data !== null ? data.data.filter((achieve) => achieve.date.includes(selected)) : null,
loaded: true,
})
}
}
componentDidMount() {
this._unsubscribe = this.props.navigation.addListener('focus',() => {
console.log('ok')
const UserStatus=this.status()
if(UserStatus){
this.GetData()
}
});
}
_onRefresh=async()=> {
try {
this.setState({refreshing: true});
this.setState(({ refreshValue }) => ({
refreshValue: refreshValue + 1,
}));
this.setState({refreshing: false});
} catch (error) {
throw error
}
}
componentWillUnmount() {
this._unsubscribe();
}
shouldComponentUpdate(nextProps, nextState) {
if(this.state.data != nextState.data){
console.log('data re')
return true;
}
if(this.state.refreshValue != nextState.refreshValue || this.state.selected != nextState.selected || this.state.target != nextState.target ){
console.log('refreshing value')
return true;
}
return false
}
sendFeedBack=async()=>{
const {feedbackText} = this.state
this.validate({
feedbackText: {minlength:3, maxlength:4000},
});
if(!this.isFieldInError('feedbackText')){
const request = await feedback(feedbackText)
if(request.status == 200){
this.setState({
feedbackText:"",
visible:false
})
}
}
}
flag = (date) => {
items = this.state.data !== null ? this.state.data.filter((achieve) => achieve.date.includes(date)) : null
let Professional = false
let Personal = false
if (!!items) {
items.map(item => {
if (item.flag == 1) { Professional = true } else if (item.flag == 2) { Personal = true }
})
if (Professional && Personal) {
return <>
<Text> <Icon name="flag-o" size={10} color="#ff6666" /> </Text>
<Text> <Icon name="star-o" size={10} color="#cc80ff" /> </Text>
</>
} else if (Professional) {
return <Text> <Icon name="flag-o" size={10} color="#ff6666" /> </Text>
} else if (Personal) {
return <Text> <Icon name="star-o" size={10} color="#cc80ff" /> </Text>
}
}
}
week = () => {
const { date, selected,loaded } = this.state
const week = this.state.date.week()
if(loaded){
return (
<>
{week.map((day, index) => {
return (
selected === week[index].plenaDiem ?
<LinearGradient key={index} colors={['#EBDDFD', '#DFDCFF']} start={[0, 1]} end={[1, 0]} style={{ borderRadius: 12 }}>
<TouchableOpacity
key={index}
style={[styles.weekday]}
onPress={() => { this.setState({ selected: week[index].plenaDiem }) }}
disabled={week[index].enable}
>
<Text style={styles.name} >{week[index].dies}</Text>
<Text style={[styles.num, { color: week[index].color }]} >{week[index].diem}</Text>
<View style={styles.flags}>
{this.flag(week[index].plenaDiem)}
</View>
</TouchableOpacity>
</LinearGradient>
:
<TouchableOpacity
key={index}
style={[styles.weekday]}
onPress={() => {
console.log(this.state.target)
this.setState({
selected: week[index].plenaDiem,
target:this.state.data !== null ? this.state.data.filter((achieve) => achieve.date.includes(week[index].plenaDiem)) : null,
})
}}
disabled={week[index].enable}
>
<Text style={styles.name} >{week[index].dies}</Text>
<Text style={[styles.num, { color: week[index].color }]} >
{week[index].diem}
</Text>
<View style={styles.flags}>
{this.flag(week[index].plenaDiem)}
</View>
</TouchableOpacity>
)
})
}
</>
)
}
}
render() {
const { data, date, visible, selected, filter, loaded,feedbackText,refreshing,target } = this.state
// let render = data !== null ? data.filter((achieve) => achieve.date.includes(selected)) : null
// if (filter !== 3 && render !== null) {
// render = render.filter((item) => item.flag == filter)
// }
return (
<>
<View style={styles.header} >
<View style={styles.top}>
<View style={styles.icon}>
<Image source={require('../../assets/header/CalendarIcon.png')} />
<Text style={styles.day}>{date.day()}</Text>
</View>
<View style={styles.items}><Image source={require('../../assets/header/medalLogo.png')} /></View>
<View style={styles.items}><IconButton icon='question' style={styles.question} color={"#000"} size={16} onPress={() => this.setState({ visible: true })} /></View>
</View>
<Modal
visible={visible}
backdropStyle={styles.backdrop}
onBackdropPress={() => this.setState({ visible: false })}>
<Card disabled={true} style={{backgroundColor:"#FFF",width:wp('90%'),borderRadius:10}}>
<Input
name='feedbackText'
value={feedbackText}
style={styles.feedbackText}
multiline={true}
maxLength={4000}
placeholder="tell us about you expermenit"
onChangeText={(text) => { this.setState({
feedbackText: text,
}) }}
/>
<Button
disabled={feedbackText.length<3?true:false}
onPress={() => {this.sendFeedBack()}}>
subimt
</Button>
</Card>
<View style={[styles.close]}>
<AntDesign name={"closecircleo"} color="#000" onPress={() => this.setState({ visible: false })} size={25} />
</View>
</Modal>
<ScrollView
contentContainerStyle={styles.scrollView}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={this._onRefresh.bind(this)}
/>
}
>
<View style={styles.month}>
<Text style={styles.monthName}>{date.monthName()}</Text>
</View>
<View style={styles.week}>
{loaded ? this.week() : <LoadingScreen/>}
</View>
</ScrollView>
</View>
<View style={styles.container} >
<View style={styles.achieve}>
<View>
{/* <SwitchSelector
options={options}
initial={0}
style={styles.switch}
buttonColor={"#fff"}
textColor={"#AB9CB3"}
selectedColor={"#000"}
buttonMargin={3}
imageStyle={styles.switchicon}
backgroundColor={"#F0F1F8"}
onPress={value => this.setState({ filter: value })}
/> */}
</View>
<View style={styles.count}>
<Text style={styles.countText}>you have achieved {target !== null ? target.length : null}</Text>
</View>
</View>
<View style={styles.cards}>
<Cards type={true} data={target} storage={data} handle={this.handleUpdate} />
</View>
</View>
</>
)
}
}
this is calendar component when run it no thing to display but data can be in console log. i can show data there, I need to hit Ctrl+s to refresh expo 'fast refresh' to show data in simulator
I have load Logic in render section but issue is still need fix
any suggestions?
this screen before hit Ctrl+s data is already in state but not rendering "first run"
here after hit Ctrl+s to refresh screen to show data

How to pass props to FlatList with renderScene in react-native-tab-view?

I'm a newbie in React Native and trying to pass props to ListHeaderComponent in FlatList
Here's the code:
const FirstRoute = (props) => {
const _renderHeader = () => {
return(
<View>
{props.isFollowed &&
<TouchableOpacity onPress={props.onSubmit}>
<Text>You have followed this person</Text>
</TouchableOpacity> }
</View>
)
}
return(
<View style={[styles.scene, { backgroundColor: '#ff4081' }]}>
<FlatList
data={data}
keyExtractor={item => item.id}
renderItem={itemData => ( <Image source={itemData.item.id} style={{height: WIDTH/3, width: WIDTH/3}} />)}
ListHeaderComponent={_renderHeader}
/>
</View>
)
};
const SecondRoute = () => (
<View style={[styles.scene, { backgroundColor: '#673ab7' }]} />
);
const initialLayout = { width: Dimensions.get('window').width };
export default function Parent() {
const [index, setIndex] = React.useState(0);
const [routes] = useState([
{ key: 'first', title: 'First' },
{ key: 'second', title: 'Second' },
]);
const [_isFollowed, setIsFollowed] = useState(false);
const _onSubmit = () => {
...
setIsfollowed(true)
}
const renderScene = ({route}) => {
switch(route.key){
case 'first': return <FirstRoute {...props} onSubmit={_onSubmit} isFollowed={_isFollowed} />
case 'second': return <SecondRoute {...props} />
}
};
return (
<TabView
navigationState={{ index, routes }}
renderScene={renderScene}
onIndexChange={setIndex}
initialLayout={initialLayout}
/>
);
}
But when I save it, the screen logs the error: Can't find the value of isFollowed
I think the problem is at the way I pass the props. I'm still learning it. Since when I delete the ListHeaderComponent, the FlatList still generates the list of images well. And I don't know if it has something to do with renderScene
I really don't understand why
Please help me. Thank you very much
Let me get this straight. You need to render _renderHeader dinamically based on _isFollowed state. So, you passed to the first route as props your _onSubmit function and _isFollowed state in order to get to access them at _renderHeader. Right?
As I see you actually doesn't need to do it once your _renderHeader has direct access to both _isFollowed state and _onSubmit function. Try it out as bellow:
export default function Parent() {
const [index, setIndex] = React.useState(0);
const [routes] = useState([
{ key: 'first', title: 'First' },
{ key: 'second', title: 'Second' },
]);
const [_isFollowed, setIsFollowed] = useState(false);
const initialLayout = { width: Dimensions.get('window').width };
function _onSubmit() {
setIsFollowed(true);
}
function _renderHeader() {
return (
<View>
{_isFollowed &&
<TouchableOpacity onPress={_onSubmit}>
<Text>You have followed this person</Text>
</TouchableOpacity> }
</View>
);
}
const FirstRoute = () => {
return(
<View style={[styles.scene, { backgroundColor: '#ff4081' }]}>
<FlatList
data={data}
keyExtractor={item => item.id}
renderItem={itemData => ( <Image source={itemData.item.id} style={{height: WIDTH/3, width: WIDTH/3}} />)}
ListHeaderComponent={_renderHeader}
/>
</View>
)
};
const SecondRoute = () => (
<View style={[styles.scene, { backgroundColor: '#673ab7' }]} />
);
const renderScene = ({route}) => {
switch(route.key){
case 'first': return <FirstRoute />
case 'second': return <SecondRoute />
}
};
return (
<TabView
navigationState={{ index, routes }}
renderScene={renderScene}
onIndexChange={setIndex}
initialLayout={initialLayout}
/>
);
}
Other point I don't understand in your code and couldn't check cause I didn't try to run it was the function bellow:
function _renderHeader() {
return (
<View>
{_isFollowed &&
<TouchableOpacity onPress={_onSubmit}>
<Text>You have followed this person</Text>
</TouchableOpacity> }
</View>
);
}
If you want to render TouchableOpacity just in case _isFollowed is true you should do it using ternary operator like so:
function _renderHeader() {
return (
<View>
{_isFollowed ?
<TouchableOpacity onPress={_onSubmit}>
<Text>You have followed this person</Text>
</TouchableOpacity> }
: <></>
}
</View>
);
}

Unable to Type in <Formik> Field

interface FormValues {
friendEmail: string;
}
const initialValues: FormValues = {
friendEmail: '',
};
export const Page: React.FunctionComponent<PageProps> = ({
toggleShowPage,
showPage,
}) => {
const [errorMessage, setErrorMessage] = useState('');
const validationSchema = emailValidationSchema;
useEffect(() => {
if (showPage) return;
initialValues.friendEmail = '';
}, [showPage]);
const [
createUserRelationMutation,
{
data: addingFriendData,
loading: addingFriendLoading,
error: addingFriendError,
called: isMutationCalled,
},
] = useCreateUserRelationMutation({
onCompleted: (data: any) => {
showAlert();
},
});
const addFriend = React.useCallback(
(id: Number) => {
console.log('Whats the Id', id);
createUserRelationMutation({
variables: {
input: { relatedUserId: id, type: RelationType.Friend, userId: 7 },
},
});
},
[createUserRelationMutation],
);
const getFriendId = React.useCallback(
(data: any) => {
//console.log('Email', initialValues.friendEmail);
if (data) {
if (data.users.nodes.length == 0) {
console.log('No user');
setErrorMessage('User Not Found');
Alert.alert('User Not Found');
} else {
console.log('ID', data.users.nodes[0].id);
addFriend(Number(data.users.nodes[0].id));
}
}
},
[addFriend],
//[friendEmail, addFriend],
);
const [loadUsers] = useUsersLazyQuery({
onCompleted: getFriendId,
onError: _onLoadUserError,
});
const handleSubmitForm = React.useCallback(
(values: FormValues, helpers: FormikHelpers<FormValues>) => {
console.log('Submitted');
loadUsers({
variables: {
where: { email: values.friendEmail },
},
});
//setFriendEmail('');
values.friendEmail = '';
},
[loadUsers],
//[loadUsers, friendEmail]
);
if (!addingFriendLoading && isMutationCalled) {
if (addingFriendData) {
console.log('Checking');
}
if (addingFriendError) {
console.log('errorFriend', addingFriendError.message);
}
}
return (
<Modal
visible={showAddFriendEmailPage}
animationType="slide"
transparent={true}>
<SafeAreaView>
<View style={scaledAddFriendEmailStyles.container}>
<View style={scaledAddFriendEmailStyles.searchTopContainer}>
<View style={scaledAddFriendEmailStyles.searchTopTextContainer}>
<Text
style={scaledAddFriendEmailStyles.searchCancelDoneText}
onPress={toggleShowPage}>
Cancel
</Text>
<Text style={scaledAddFriendEmailStyles.searchTopMiddleText}>
Add Friend by Email
</Text>
<Text style={scaledAddFriendEmailStyles.searchCancelDoneText}>
Done
</Text>
</View>
<View style={scaledAddFriendEmailStyles.searchFieldContainer}>
<Formik
initialValues={initialValues}
onSubmit={handleSubmitForm}
validationSchema={validationSchema}>
{({
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
values,
}) => (
<View>
<View>
<Item style={scaledAddFriendEmailStyles.searchField}>
<TextInput
style={scaledAddFriendEmailStyles.searchText}
placeholder="Email"
onChangeText={handleChange('friendEmail')}
//onChangeText={e => console.log('Workinggg')}
onBlur={handleBlur('friendEmail')}
value={values.friendEmail}
autoCapitalize="none"
/>
{/* <Field
component={Input}
name='friendEmail'
placeholder="Email"
//handleChange={handleChange}
handleBlur={handleBlur}
//onChange={handleChange}
//onChangeText={handleChange('friendEmail')}
//onBlur={handleBlur('friendEmail')}
value={values.friendEmail}
autoCapitalize="none"
/> */}
</Item>
</View>
<View>
<Button
onPress={handleSubmit}>
<Text>
Add Friend{' '}
</Text>
</Button>
</View>
</View>
)}
</Formik>
</View>
</View>
</View>
</SafeAreaView>
</Modal>
);
};
Why am I unable to write anything inside my Input field? I have tried using onChangeand handleChangeboth but it doesn't make a difference. Other SO answers suggested that I should remove value but examples of Formik usage that I see online suggest otherwise.
I am trying to follow this for my Formik validation:
https://heartbeat.fritz.ai/build-and-validate-forms-in-react-native-using-formik-and-yup-6489e2dff6a2
EDIT:
I also tried with setFieldValuebut I still cannot type anything.
const initialValues: FormValues = {
friendEmail: '',
};
export const AddFriendEmailPage: React.FunctionComponent<AddFriendEmailPageProps> = ({
toggleShowPage,
showAddFriendEmailPage,
}) => {
const [errorMessage, setErrorMessage] = useState('');
const validationSchema = emailValidationSchema;
useEffect(() => {
if (showAddFriendEmailPage) return;
initialValues.friendEmail = '';
}, [showAddFriendEmailPage]);
const _onLoadUserError = React.useCallback((error: ApolloError) => {
setErrorMessage(error.message);
Alert.alert('Unable to Add Friend');
}, []);
const [
createUserRelationMutation,
{
data: addingFriendData,
loading: addingFriendLoading,
error: addingFriendError,
called: isMutationCalled,
},
] = useCreateUserRelationMutation({
onCompleted: (data: any) => {
showAlert();
},
});
const addFriend = React.useCallback(
(id: Number) => {
console.log('Whats the Id', id);
createUserRelationMutation({
variables: {
input: { relatedUserId: id, type: RelationType.Friend, userId: 7 },
},
});
},
[createUserRelationMutation],
);
const getFriendId = React.useCallback(
(data: any) => {
//console.log('Email', initialValues.friendEmail);
if (data) {
if (data.users.nodes.length == 0) {
console.log('No user');
} else {
console.log('ID', data.users.nodes[0].id);
addFriend(Number(data.users.nodes[0].id));
}
}
},
[addFriend],
//[friendEmail, addFriend],
);
const [loadUsers] = useUsersLazyQuery({
onCompleted: getFriendId,
onError: _onLoadUserError,
});
const handleSubmitForm = React.useCallback(
(values: FormValues, helpers: FormikHelpers<FormValues>) => {
console.log('Submitted');
loadUsers({
variables: {
where: { email: values.friendEmail },
},
});
//setFriendEmail('');
values.friendEmail = '';
},
[loadUsers],
//[loadUsers, friendEmail]
);
return (
<Modal
visible={showPage}
animationType="slide"
transparent={true}>
<SafeAreaView>
<View style={scaledAddFriendEmailStyles.container}>
<View style={scaledAddFriendEmailStyles.searchFieldContainer}>
<Formik
initialValues={initialValues}
onSubmit={handleSubmitForm}
validationSchema={validationSchema}>
{({
handleChange,
setFieldValue,
handleBlur,
handleSubmit,
isSubmitting,
values,
}) => {
const setEmail = (friendEmail: string) => {
setFieldValue('friendEmail', friendEmail)
}
return(
<View>
<View>
<Item>
<TextInput
placeholder="Email"
onChangeText={setEmail}
onBlur={handleBlur('friendEmail')}
value={values.friendEmail}
autoCapitalize="none"
/>
</Item>
</View>
<View >
<Button
onPress={handleSubmit}>
<Text >
Add Friend{' '}
</Text>
</Button>
</View>
</View>
)}}
</Formik>
</View>
</View>
</View>
</SafeAreaView>
</Modal>
);
};
Formik's Field component doesn't support React native yet. Check this github issue for more details
However you can make use of TextInput in place of field and use it with onChangeText handler
<Formik
initialValues={initialValues}
onSubmit={handleSubmitForm}
validationSchema={validationSchema}>
{({
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
values,
}) => (
<View>
<View>
<Item style={scaledAddFriendEmailStyles.searchField}>
<TextInput
placeholder="Email"
onChangeText={handleChange('friendEmail')}
onBlur={handleBlur('friendEmail')}
value={values.friendEmail}
/>
</Item>
</View>
<View >
<Button
onPress={handleSubmit}
>
<Text >
Add Friend{' '}
</Text>
</Button>
</View>
</View>
)}
</Formik>
you can read more about Formik's usage with react-native in its documentation here
try this:
<Input
placeholder="Email"
onChange={e => setFieldValue('friendEmail', e.currentTarget.value)}
onBlur={handleBlur}
value={values.friendEmail}
autoCapitalize="none"
/>
I think there are a couple of issues in your codebase.
onChangeText={handleChange('friendEmail')}. It will trigger the handleChange while rendering the component not when you are actualy typing in the input box.
handleChange function of Formik takes React.ChangeEvent instead of value. Check here . While onChangeText of react-native provides changed text of the input not event. Check here
You can use setFieldValue function for this case:
<Formik
initialValues={initialValues}
onSubmit={handleSubmitForm}
validationSchema={validationSchema}>
{({
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
values,
setFieldValue
}) => {
const setEmail = (email) => {
setFieldValue('friendEmail', email)
}
return (
<View>
<View>
<Item style={scaledAddFriendEmailStyles.searchField}>
<TextInput
placeholder="Email"
onChangeText={setEmail}
value={values.friendEmail}
/>
</Item>
</View>
</View>
)
}}
</Formik>
Please Note: I've never used formik with react-native. Just trying to connect the dots.
Formik now works fine with React Native, but another thing to be aware of is that the name in your form control must match the name of the property in the schema used by Formik.
For example, if using the following Yup schema:
const schema = yup.object({
personName: yup.string().required('Name required')
});
Then the following won't work because the Yup schema (personName) and the form control (nameofPerson) don't match; the user won't be able to type into the field:
<Form.Control
name="nameOfPerson"
value={values.personName}
onChange={handleChange}
onBlur={handleBlur}
type="text"
isValid={!errors.personName && !!touched.personName}
isInvalid={!!errors.personName && !!touched.personName}
/>
To make it work, the name should be the same as the Yup property; in this case, personName:
<Form.Control
name="personName"
value={values.personName}
onChange={handleChange}
onBlur={handleBlur}
type="text"
isValid={!errors.personName && !!touched.personName}
isInvalid={!!errors.personName && !!touched.personName}
/>
This example is using React-Bootstrap Form.Control but should apply to any manner of creating form controls.

Render from a callback function - typescript

While using a graphql query, I am calling a showUsers function which is supposed to show all the users (the stying is done so that they can appear as boxes). However, currently nothing shows up.
I am using a functional component, not class component.
This function is called after my handleSubmitForm. Here I call showUsers.
const getFriendId = React.useCallback(
(data) => {
if (data) {
if (data.users.nodes.length == 0) {
Alert.alert('User Not Found');
} else {
const numberOfUsers = data.users.nodes.length;
showUsers(data, numberOfUsers);
addFriend(Number(data.users.nodes[0].id));
}
}
},
[addFriend],
);
showUsers():
const showUsers = React.useCallback(
(data: UsersLazyQueryHookResult, numberOfUsers: Number) => {
for (var i = 0; i < numberOfUsers; i++) {
const userId = data.users.nodes[i].id;
const userName = (data.users.nodes[i].firstName).concat((data.users.nodes[i].lastName));
return(
<View style={styles.friends}>
<View style={styles.item}>
<Text>{userName}</Text>
</View>
</View>
)
}
},
[createUserRelationMutation],
);
This is how my form looks like. I guess I have to make an edit here but I am not sure how.
return (
<Modal
visible={showAddFriendEmailPage}
animationType="slide"
transparent={true}>
<SafeAreaView>
<View style={styles.container}>
<View style={styles.searchTopContainer}>
<View>
<Formik
initialValues={initialValues}
onSubmit={handleSubmitForm}
validationSchema={validationSchema}>
{({ handleChange, handleBlur, handleSubmit, values }) => (
<View style={styles.searchFieldContainer}>
<View style={styles.form}>
<FieldInput
handleChange={handleChange}
handleBlur={handleBlur}
value={values.email}
fieldType="email"
/>
<ErrorMessage
name="email"
render={msg => (
<Text style={styles.errorText}>{msg}</Text>
)}
/>
</View>
<View style={styles.buttonContainer}>
<Button
onPress={handleSubmit}>
<Text >Add Friend </Text>
</Button>
</View>
</View>
)}
</Formik>
</View>
</View>
</View>
</SafeAreaView>
</Modal>
);
};
Note: I only want them to show up below the button, after I submit the form.
EDIT:
I am trying this but I have a few problems:
Even when there's only one user, I see the LOOPoutput on the console at least 4 times.
Once the query and mutation run successfully and a user is also rendered/displayed, I can no longer press the button again. Which means that I can no longer submit the form and re-run queries or mutations with a different email input.
export const AddFriendEmailPage: React.FunctionComponent<AddFriendEmailPageProps> = ({
toggleShowPage,
showAddFriendEmailPage,
}) => {
const initialValues: FormValues = {
email: '',
};
const [errorMessage, setErrorMessage] = useState('');
const [userData, setUserData] = useState<UsersLazyQueryHookResult>('');
const [numberOfUsers, setNumberOfUsers] = useState('');
const validationSchema = emailValidationSchema;
useEffect(() => {
setUserData(userData);
setNumberOfUsers(numberOfUsers);
}, [userData, numberOfUsers]);
const showAlert = () => {
Alert.alert('Friend Added');
};
useEffect(() => {
if (showAddFriendEmailPage) return;
initialValues.email = '';
}, [showAddFriendEmailPage]);
const _onLoadUserError = React.useCallback((error: ApolloError) => {
setErrorMessage(error.message);
Alert.alert('Unable to Add Friend');
}, []);
const [
createUserRelationMutation,
{
data: addingFriendData,
loading: addingFriendLoading,
error: addingFriendError,
called: isMutationCalled,
},
] = useCreateUserRelationMutation({
onCompleted: (data: CreateUserRelationMutationResult) => {
showAlert();
},
});
const showUsers = React.useCallback(
(data: UsersLazyQueryHookResult, numberOfUsers: Number) => {
console.log('Number of Users in Loop: ', numberOfUsers);
for (var i = 0; i < numberOfUsers; i++) {
const userId = data.users.nodes[i].id;
const userName = ((data.users.nodes[i].firstName).concat(' ')).concat(data.users.nodes[i].lastName);
console.log('Whats the Id', userId);
console.log('UserName', userName);
console.log('Loop');
return(
<View style={styles.friends}>
<View style={styles.item}>
<Text>{userName}</Text>
</View>
</View>
)
}
},
[createUserRelationMutation],
);
const addFriend = React.useCallback(
(id: Number) => {
console.log('Whats the Id', id);
createUserRelationMutation({
variables: {
input: { relatedUserId: id, type: RelationType.Friend, userId: 7 },
},
});
},
[createUserRelationMutation],
);
const getFriendId = React.useCallback(
(data: UsersLazyQueryHookResult) => {
if (data) {
if (data.users.nodes.length == 0) {
setErrorMessage('User Not Found');
Alert.alert('User Not Found');
} else {
setUserData(data);
//const numberOfUsers = data.users.nodes.length;
setNumberOfUsers(data.users.nodes.length);
showUsers(data, Number(numberOfUsers));
addFriend(Number(data.users.nodes[0].id));
}
}
},
[addFriend],
);
const [loadUsers] = useUsersLazyQuery({
onCompleted: getFriendId,
onError: _onLoadUserError,
});
const handleSubmitForm = React.useCallback(
(values: FormValues, helpers: FormikHelpers<FormValues>) => {
console.log('Submitted');
loadUsers({
variables: {
where: { email: values.email },
},
});
values.email = '';
},
[loadUsers],
);
if (!addingFriendLoading && isMutationCalled) {
if (addingFriendError) {
setErrorMessage(addingFriendError.message);
Alert.alert('Unable to Add Friend');
}
}
return (
<Modal
visible={showAddFriendEmailPage}
animationType="slide"
transparent={true}>
<SafeAreaView>
<View style={styles.container}>
<View style={styles.searchTopContainer}>
<View style={styles.searchTopTextContainer}>
<Text
style={styles.searchCancelDoneText}
onPress={toggleShowPage}>
Cancel
</Text>
<Text style={styles.searchTopMiddleText}>
Add Friend by Email
</Text>
<Text style={styles.searchCancelDoneText}>Done</Text>
</View>
<View>
<Formik
initialValues={initialValues}
onSubmit={handleSubmitForm}
validationSchema={validationSchema}>
{({ handleChange, handleBlur, handleSubmit, values }) => (
<View style={styles.searchFieldContainer}>
<View style={styles.form}>
<FieldInput
handleChange={handleChange}
handleBlur={handleBlur}
value={values.email}
fieldType="email"
/>
<ErrorMessage
name="email"
render={msg => (
<Text style={styles.errorText}>{msg}</Text>
)}
/>
</View>
<View style={styles.buttonContainer}>
<Button
rounded
style={styles.button}
onPress={handleSubmit}>
<Text style={styles.text}>Add Friend </Text>
</Button>
</View>
</View>
)}
</Formik>
</View>
{showUsers(userData, Number(numberOfUsers))}
</View>
</View>
</SafeAreaView>
</Modal>
);
};
While using a graphql query, I am calling a showUsers function which
is supposed to show all the users (the stying is done so that they can
appear as boxes). However, currently nothing shows up.
A function call showUsers(data, numberOfUsers); can't just show items. You have to render it somewhere.
<View style={styles.buttonContainer}>
<Button
rounded
style={styles.button}
onPress={handleSubmit}>
<Text style={styles.text}>Add Friend </Text>
</Button>
</View>
{showUsers(data, numberOfUsers)}
But this also don't work straight away because you don't have data variable in this context. You have to use useState. I don't know if you can use React.useCallback function to return component this way. I would change showUsers(data, numberOfUsers) to
separate functional component.

undo re-rendering when exiting screen

In my code, I take an email as an input and run a graphql query. Using the graphql query results, I use my showUsersfunction to render some components. When I hit canceland go to the previous screen (toggling), the rendered objects (results of query) should disappear. When I come back to the screen, I am still seeing them. How can I reset them while exiting?
Currently this is what I am doing in my return
{showUsers(userData, Number(numberOfUsers))}
Overview of my code:
export const Page: React.FunctionComponent<PageProps> = ({
toggleShowPage,
showAddFriendEmailPage,
}) => {
const [userData, setUserData] = useState<UsersLazyQueryHookResult>('');
const [numberOfUsers, setNumberOfUsers] = useState('');
const validationSchema = emailValidationSchema;
const showUsers = React.useCallback(
(data: UsersLazyQueryHookResult, numberOfUsers: Number) => {
for (var i = 0; i < numberOfUsers; i++) {
const userId = data.users.nodes[i].id;
const userName = data.users.nodes[i].firstName
.concat(' ')
.concat(data.users.nodes[i].lastName);
return (
<View style={styles.friends}>
<View style={styles.item}>
<Text style={styles.userName}>{userName}</Text>
<View style={styles.addButtonContainer}>
<Button rounded style={styles.addButton}
//onPress={() => addFriend(Number(data.users.nodes[i].id))}
>
</Button>
</View>
</View>
</View>
);
}
},
[createUserRelationMutation],
);
const addFriend = React.useCallback(
(id: Number) => {
console.log('Whats the Id', id);
createUserRelationMutation({
variables: {
input: { relatedUserId: id, type: RelationType.Friend, userId: 7 },
},
});
},
[createUserRelationMutation],
);
const getFriendId = React.useCallback(
(data: UsersLazyQueryHookResult) => {
if (data) {
if (data.users.nodes.length == 0) {
Alert.alert('User Not Found');
} else {
setUserData(data);
setNumberOfUsers(data.users.nodes.length);
}
}
},
[addFriend],
);
const [loadUsers] = useUsersLazyQuery({
onCompleted: getFriendId,
onError: _onLoadUserError,
});
const handleSubmitForm = React.useCallback(
(values: FormValues, helpers: FormikHelpers<FormValues>) => {
console.log('Submitted');
loadUsers({
variables: {
where: { email: values.email },
},
});
values.email = '';
},
[loadUsers],
);
return (
<Modal
visible={showAddFriendEmailPage}
animationType="slide"
transparent={true}>
<SafeAreaView>
<View style={styles.container}>
<View style={styles.searchTopContainer}>
<View style={styles.searchTopTextContainer}>
<Text
style={styles.searchCancelDoneText}
onPress={toggleShowPage}>
Cancel
</Text>
<Text style={styles.searchTopMiddleText}>
Add Friend by Email
</Text>
<Text style={styles.searchCancelDoneText}>Done</Text>
</View>
<View>
<Formik
initialValues={initialValues}
onSubmit={handleSubmitForm}
validationSchema={validationSchema}>
{({ handleChange, handleBlur, handleSubmit, values }) => (
<View style={styles.searchFieldContainer}>
<View style={styles.form}>
<FieldInput
handleChange={handleChange}
handleBlur={handleBlur}
value={values.email}
fieldType="email"
/>
<ErrorMessage
name="email"
render={msg => (
<Text style={styles.errorText}>{msg}</Text>
)}
/>
</View>
<View style={styles.buttonContainer}>
<Button
rounded
style={styles.button}
onPress={handleSubmit}>
<Text style={styles.text}>Search </Text>
</Button>
</View>
</View>
)}
</Formik>
</View>
{showUsers(userData, Number(numberOfUsers))}
</View>
</View>
</SafeAreaView>
</Modal>
);
};
This worked for me:
const [isSubmitted, setIsSubmitted] = useState(false);
const handleSubmitForm = React.useCallback(
(values: FormValues, helpers: FormikHelpers<FormValues>) => {
setIsSubmitted(true);
...
},
[loadUsers],
);
{isSubmitted && showUsers(userData, Number(numberOfUsers))}
Upon cancelling, we can setIsSubmitted to false.

Categories

Resources