I have a function called addFunc in my main Class. This class calls the RenderItem function to display a list of items. Each item has an onClick that should execute the addFunc function.
I am unable to call the addFunc function from within my RenderItem function because they are in different components. How do I get past this?
This is a summary of my code:
const selectedData = []
class Search extends Component {
constructor(props) {
super(props);
this.addFunc = this.addFunc.bind(this);
}
addFunc(resultdata){
console.log(resultdata)
selectedData = [...selectedData, resultdata]
console.log(selectedData)
};
render() {
return (
<ReactiveList
componentId="results"
dataField="_score"
pagination={true}
react={{
and: ["system", "grouping", "unit", "search"]
}}
size={10}
noResults="No results were found..."
renderItem={RenderItem}
/>
);
const RenderItem = (res, addFunc) => {
let { unit, title, system, score, proposed, id } = {
title: "maker_tag_name",
proposed: "proposed_standard_format",
unit: "units",
system: "system",
score: "_score",
id: "_id"
};
const resultdata = {id, title, system, unit, score, proposed}
return (
<Button
shape="circle"
icon={<CheckOutlined />}
style={{ marginRight: "5px" }}
onClick={this.addFunc()}
/>
);
}
You can wrap RenderItem component with another component and then render it,
const Wrapper = cb => {
return (res, triggerClickAnalytics) => (
<RenderItem
res={res}
triggerClickAnalytics={triggerClickAnalytics}
addFunc={cb}
/>
);
};
and renderItem of ReactiveList would be: renderItem={Wrapper(this.addFunc)}
then RenderItem component would be
const RenderItem = ({ res, triggerClickAnalytics, addFunc }) => {
...
see sandbox: https://codesandbox.io/s/autumn-paper-337qz?fontsize=14&hidenavigation=1&theme=dark
You can pass a callback function defined in the parent as a prop to the child component
class Parent extends React.Component {
sayHello(name) => {
console.log("Hello " + name)
}
render() {
return <Child1 parentCallback = {this.sayHello}/>
}
}
and then call it from the child component
class Child1 extends React.Component{
componentDidMount() {
this.props.parentCallback("Foo")
}
render() {
return <span>child component</span>
}
};
I have a component that is giving me the following issues:
TEST STEPS:
Login to Mobile.
On the Activity Feed, answer the first Get Involved question.
Scroll to the last Get Involved question and answer it.
Scroll back to the first Get Involved question that was answered.
EXPECTED RESULTS:
The answer for the first Get Involved question should still be selected.
ACTUAL RESULTS:
It is not selected.
So it seems the issue is the callback that updates some state on the parent, but the parent is not passing the yes/no prop to this component and it's unmounting to spare me rendering.
On the backend, in the database, the answers are being recorded, but it's not persisting in the UI. I noticed that the helper functions below, specifically the this.props.onPress() return undefined.
class GetInvolvedFeedCard extends PureComponent {
static propTypes = {
onPress: PropTypes.func.isRequired,
style: PropTypes.oneOfType([PropTypes.number, PropTypes.object]),
title: PropTypes.string.isRequired
};
constructor(props) {
super(props);
const helper = `${
this.props.title.endsWith("?") ? "" : "."
} Your NFIB preferences will be updated.`;
this.state = {
noSelected: false,
yesSelected: false,
helper
};
}
_accept = () => {
this.setState({ yesSelected: true, noSelected: false }, () => {
this.props.onPress(true);
});
};
_decline = () => {
this.setState({ noSelected: true, yesSelected: false }, () => {
this.props.onPress(false);
});
};
render() {
return (
<Card style={this.props.style}>
<View style={feedContentStyles.header}>
<View style={feedContentStyles.contentType}>
<Text style={feedContentStyles.title}>{"GET INVOLVED"}</Text>
</View>
</View>
<Divider />
<View style={feedContentStyles.content}>
<View style={styles.content}>
<Text style={styles.blackTitle}>
{this.props.title}
<Text style={styles.italicText}>{this.state.helper}</Text>
</Text>
</View>
<View style={styles.footer}>
<TouchableOpacity onPress={this._decline}>
<Text
style={[
styles.btnText,
styles.noBtn,
this.state.noSelected ? styles.selected : null
]}
>
{"NO"}
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this._accept}>
<Text
style={[
styles.btnText,
this.state.yesSelected ? styles.selected : null
]}
>
{"YES"}
</Text>
</TouchableOpacity>
</View>
</View>
</Card>
);
}
}
So it appears that the state is being managed by the parent component as opposed to Redux.
What is unclear is, whether or not it is unmounting the component that defines onPress. It sounds like it is.
Just scrolling, so there is an activity feed composed of cards some of them render boolean type questions
do you want to get involved? no yes
When a user selects either response, then scrolls down a certain amount and then scrolls back up to that same question, it's like the user never answered it. I noticed when the user selects NO, the this.props.handleUpdateGetInvolved({ involved: items }) from _handleGetInvolved function is not fired only when the user selects YES. Referring to this:
_handleGetInvolved = (response, entity) => {
if (response !== entity.IsSelected) {
const isTopic = entity.Category !== "GetInvolved";
const items = [
{
...entity,
IsSelected: response
}
];
if (isTopic) {
this.props.handleUpdateTopics({ topics: items });
} else {
this.props.handleUpdateGetInvolved({ involved: items });
}
}
};
the helper functions themselves for each answer always returns undefined inside the GetInvolvedFeedCard component:
_accept = () => {
this.setState({ yesSelected: true, noSelected: false }, () => {
this.props.onPress(true);
console.log(
"this is the accept helper function: ",
this.props.onPress(true)
);
});
};
_decline = () => {
this.setState({ noSelected: true, yesSelected: false }, () => {
this.props.onPress(false);
console.log(
"this is the decline helper function: ",
this.props.onPress(false)
);
});
};
render() {
return (
<Card style={this.props.style}>
<View style={feedContentStyles.header}>
<View style={feedContentStyles.contentType}>
<Text style={feedContentStyles.title}>{"GET INVOLVED"}</Text>
</View>
</View>
<Divider />
<View style={feedContentStyles.content}>
<View style={styles.content}>
<Text style={styles.blackTitle}>
{this.props.title}
<Text style={styles.italicText}>{this.state.helper}</Text>
</Text>
</View>
<View style={styles.footer}>
<TouchableOpacity onPress={this._decline}>
<Text
style={[
styles.btnText,
styles.noBtn,
this.state.noSelected ? styles.selected : null
]}
>
{"NO"}
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this._accept}>
<Text
style={[
styles.btnText,
this.state.yesSelected ? styles.selected : null
]}
>
{"YES"}
</Text>
</TouchableOpacity>
</View>
If I am not mistaken all this is being rendered overall by the ActivityFeed component:
const { height } = Dimensions.get("window");
export class ActivityFeed extends PureComponent {
static propTypes = {
displayAlert: PropTypes.bool,
feed: PropTypes.array,
fetchFeed: PropTypes.func,
getCampaignDetails: PropTypes.func,
handleContentSwipe: PropTypes.func,
handleUpdateGetInvoved: PropTypes.func,
handleUpdateTopics: PropTypes.func,
hideUndoAlert: PropTypes.func,
lastSwippedElement: PropTypes.object,
loading: PropTypes.bool,
navigation: PropTypes.object,
setSelectedAlert: PropTypes.func,
setSelectedArticle: PropTypes.func,
setSelectedEvent: PropTypes.func,
setSelectedSurvey: PropTypes.func.isRequired,
undoSwipeAction: PropTypes.func,
userEmailIsValidForVoterVoice: PropTypes.bool
};
constructor(props) {
super(props);
this.prompted = false;
this.state = {
refreshing: false,
appState: AppState.currentState
};
}
async componentDidMount() {
AppState.addEventListener("change", this._handleAppStateChange);
if (!this.props.loading) {
const doRefresh = await cache.shouldRefresh("feed");
if (this.props.feed.length === 0 || doRefresh) {
this.props.fetchFeed();
}
cache.incrementAppViews();
}
}
componentWillUnmount() {
AppState.removeEventListener("change", this._handleAppStateChange);
}
_handleAppStateChange = async appState => {
if (
this.state.appState.match(/inactive|background/) &&
appState === "active"
) {
cache.incrementAppViews();
const doRefresh = await cache.shouldRefresh("feed");
if (doRefresh) {
this.props.fetchFeed();
}
}
this.setState({ appState });
};
_keyExtractor = ({ Entity }) =>
(Entity.Key || Entity.Id || Entity.CampaignId || Entity.Code).toString();
_gotoEvent = event => {
cache.setRouteStarter("MainDrawer");
this.props.setSelectedEvent(event);
const title = `${event.LegislatureType} Event`;
this.props.navigation.navigate("EventDetails", { title });
};
_gotoSurveyBallot = survey => {
cache.setRouteStarter("MainDrawer");
this.props.setSelectedSurvey(survey);
this.props.navigation.navigate("SurveyDetails");
};
_gotoArticle = article => {
cache.setRouteStarter("MainDrawer");
this.props.setSelectedArticle(article);
this.props.navigation.navigate("ArticleDetails");
};
_onAlertActionButtonPress = async item => {
cache.setRouteStarter("MainDrawer");
await this.props.setSelectedAlert(item.Entity);
this.props.getCampaignDetails();
if (this.props.userEmailIsValidForVoterVoice) {
this.props.navigation.navigate("Questionnaire");
} else {
this.props.navigation.navigate("UnconfirmedEmail");
}
};
_onSwipedOut = (swippedItem, index) => {
this.props.handleContentSwipe(this.props, { swippedItem, index });
};
_handleGetInvolved = (response, entity) => {
if (response !== entity.IsSelected) {
const isTopic = entity.Category !== "GetInvolved";
const items = [
{
...entity,
IsSelected: response
}
];
if (isTopic) {
this.props.handleUpdateTopics({ topics: items });
} else {
this.props.handleUpdateGetInvoved({ involved: items });
}
}
};
renderItem = ({ item, index }) => {
const { Type, Entity } = item;
if (Type === "EVENT") {
return (
<SwippableCard onSwipedOut={() => this._onSwipedOut(item, index)}>
<EventFeedCard
style={styles.push}
mainActionButtonPress={() => this._gotoEvent(Entity)}
event={Entity}
/>
</SwippableCard>
);
}
if (["SURVEY_SURVEY", "SURVEY_BALLOT"].includes(Type)) {
return (
<SwippableCard onSwipedOut={() => this._onSwipedOut(item, index)}>
<SurveyBallotFeedCard
style={styles.push}
survey={Entity}
handleViewDetails={() => this._gotoSurveyBallot(Entity)}
/>
</SwippableCard>
);
}
if (Type === "SURVEY_MICRO") {
return (
<SwippableCard onSwipedOut={() => this._onSwipedOut(item, index)}>
<MicroSurvey style={styles.push} selectedSurvey={Entity} />
</SwippableCard>
);
}
if (Type === "ALERT") {
return (
<SwippableCard onSwipedOut={() => this._onSwipedOut(item, index)}>
<ActionAlertFeedCard
datePosted={Entity.StartDateUtc}
style={styles.push}
title={Entity.Headline}
content={Entity.Alert}
mainActionButtonPress={() => this._onAlertActionButtonPress(item)}
secondaryActionButtonPress={() => {
this.props.setSelectedAlert(Entity);
// eslint-disable-next-line
this.props.navigation.navigate("ActionAlertDetails", {
content: Entity.Alert,
id: Entity.CampaignId,
title: Entity.Headline
});
}}
/>
</SwippableCard>
);
}
if (Type === "ARTICLE") {
return (
<SwippableCard onSwipedOut={() => this._onSwipedOut(item, index)}>
<ArticleFeedCard
content={Entity}
style={styles.push}
mainActionButtonPress={() => this._gotoArticle(Entity)}
/>
</SwippableCard>
);
}
//prettier-ignore
if (Type === 'NOTIFICATION' && Entity.Code === 'INDIVIDUAL_ADDRESS_HOME_MISSING') {
return (
<MissingAddressCard
style={styles.push}
navigate={() => this.props.navigation.navigate('HomeAddress')}
/>
);
}
if (["PREFERENCE_TOPIC", "PREFERENCE_INVOLVEMENT"].includes(Type)) {
return (
<SwippableCard onSwipedOut={() => this._onSwipedOut(item, index)}>
<GetInvolvedFeedCard
style={styles.push}
title={Entity.DisplayText}
onPress={response => this._handleGetInvolved(response, Entity)}
/>
</SwippableCard>
);
}
return null;
};
_onRefresh = async () => {
try {
this.setState({ refreshing: true });
this.props
.fetchFeed()
.then(() => {
this.setState({ refreshing: false });
})
.catch(() => {
this.setState({ refreshing: false });
});
} catch (e) {
this.setState({ refreshing: false });
}
};
_trackScroll = async event => {
try {
if (this.prompted) {
return;
}
const y = event.nativeEvent.contentOffset.y;
const scrollHeight = height * 0.8;
const page = Math.round(Math.floor(y) / scrollHeight);
const alert = await cache.shouldPromtpPushNotificationPermissions();
const iOS = Platform.OS === "ios";
if (alert && iOS && page > 1) {
this.prompted = true;
this._openPromptAlert();
}
} catch (e) {
return false;
}
};
_openPromptAlert = () => {
Alert.alert(
"Push Notifications Access",
"Stay engaged with NFIB on the issues and activities you care about by allowing us to notify you using push notifications",
[
{
text: "Deny",
onPress: () => {
cache.pushNotificationsPrompted();
},
style: "cancel"
},
{
text: "Allow",
onPress: () => {
OneSignal.registerForPushNotifications();
cache.pushNotificationsPrompted();
}
}
],
{ cancelable: false }
);
};
_getAlertTitle = () => {
const { lastSwippedElement } = this.props;
const { Type } = lastSwippedElement.swippedItem;
if (Type.startsWith("PREFERENCE")) {
return "Preference Dismissed";
}
switch (Type) {
case "EVENT":
return "Event Dismissed";
case "SURVEY_BALLOT":
return "Ballot Dismissed";
case "SURVEY_SURVEY":
return "Survey Dismissed";
case "SURVEY_MICRO":
return "Micro Survey Dismissed";
case "ARTICLE":
return "Article Dismissed";
case "ALERT":
return "Action Alert Dismissed";
default:
return "Dismissed";
}
};
render() {
if (this.props.loading && !this.state.refreshing) {
return <Loading />;
}
const contentStyles =
this.props.feed.length > 0 ? styles.content : emptyStateStyles.container;
return (
<View style={styles.container}>
<FlatList
contentContainerStyle={contentStyles}
showsVerticalScrollIndicator={false}
data={this.props.feed}
renderItem={this.renderItem}
keyExtractor={this._keyExtractor}
removeClippedSubviews={false}
onRefresh={this._onRefresh}
refreshing={this.state.refreshing}
ListEmptyComponent={() => (
<EmptyState navigation={this.props.navigation} />
)}
scrollEventThrottle={100}
onScroll={this._trackScroll}
/>
{this.props.displayAlert && (
<BottomAlert
title={this._getAlertTitle()}
onPress={this.props.undoSwipeAction}
hideAlert={this.props.hideUndoAlert}
/>
)}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
content: {
paddingHorizontal: scale(8),
paddingTop: scale(16),
paddingBottom: scale(20)
},
push: {
marginBottom: 16
}
});
const mapState2Props = ({
activityFeed,
auth: { userEmailIsValidForVoterVoice },
navigation
}) => {
return {
...activityFeed,
userEmailIsValidForVoterVoice,
loading: activityFeed.loading || navigation.deepLinkLoading
};
};
export default connect(mapState2Props, {
fetchFeed,
getCampaignDetails,
handleUpdateGetInvoved,
handleUpdateTopics,
setSelectedAlert,
setSelectedArticle,
setSelectedEvent,
setSelectedSurvey,
handleContentSwipe,
undoSwipeAction,
hideUndoAlert
})(ActivityFeed);
This is what the Get Involved card looks like:
So when the user clicks NO or YES, then scrolls that card away from view, the expectation is when they scroll that card back into view NO or YES, whichever one selected, should still be there.
Also, the answer selected only disappears when the user scrolls all the way to the bottom of the activity feed and then back up, but if the user only scrolls halfway through the activity feed cards and returns to this Get Involved card, the answer selected does not go away.
I believe the below SO article answer is exactly what is happening to me:
React Native - FlatList - Internal State.
So it seems the answer here would be to pass the answer from the application state as a prop and render based on that prop, and not the internal state of the card but I am not entirely sure what that looks like or how to put it together.
constructor(props) {
super(props);
// const helper = `${
// this.props.title.endsWith("?") ? "" : "."
// } Your NFIB preferences will be updated.`;
this.state = {
noSelected: false,
yesSelected: false,
helper
};
}
_accept = () => {
this.setState({ yesSelected: true, noSelected: false }, () => {
this.props.onPress(true);
});
};
_decline = () => {
this.setState({ noSelected: true, yesSelected: false }, () => {
this.props.onPress(false);
});
};
with:
this.state = {
// noSelected: false,
// yesSelected: false,
// helper
cardSelectedStatus: []
};
with the idea of then implementing cardSelectedStatus in my mapStateToProps
function mapStateToProps(state) {
return {cardSelectedStatus: state.};
}
but then I realized I am not sure what I am passing in as there are no action creators involved in this component, therefore no reducers
so can I use mapStateToProps if there is no action creator/reducer involved in this component?
utilizing mapStateToProps is the only way I know or its the way with the most experience I have in passing the user's input from the application state as a prop and render based on that prop, and not the internal state.
I can guess the problem. The problem is you are using something like FlatList. It will recreate the card every time you scroll it over screen, then scroll back.
So there are 2 ways to fix it:
Using ScrollView. It won't recreate cards
Move card states out of the Card component. Move them to List state. So in List state you will have something like:
this.state = {
cardSelectedStatus: [], // array [true, false, true, ...]. Mean card 0: selected, card 1: no selected,...
...
};
Then you can pass state to each card
So after several weeks of hammering away at this and posting the above question, here is what I finally honed in on:
By default the data for the preference is set to isSelected: false in the Redux state.
If I hit Yes, the Redux state is updated. This changes the isSelected to true.
If I hit No after hitting Yes, the Redux state is NOT updated, it stays isSelected: true.
So based on this, because isSelected does not have a neutral value, that is, starts out as false, which would equate to No, I cannot rely on Redux state for rendering the selection, which could have solved this.
Instead, in the interest of time, the only solution I could think of with much input from others includint tuledev, was to set <FlatList windowSize={500} />.
This is not an elegant solution but it will get FlatList to behave more like ScrollView in that preserve all the components so my component state will not get wiped out when a user scrolls to far away from it. This works without actually replacing it to ScrollView since there are properties and methods with FlatList that would not work by just dropping it into ScrollView same as it is in FlatList, for example, there is no renderItem property in ScrollView.
I have been stuck on this for ages trying to figure out how I can console log each Firebase Cloudstore document ID separately when I press onto each rendered FlatList item.
I can grab a certain key / id by using onPress={() =>{console.log(this.state.posts[0].key)}} etc. But I dont know how to grab each one separately. In essence I only want the document ID of the touchableOpacity I have pressed. Not just [0]
Screenshots are below of App layout so you can get an understanding and also code example
PostsLayout.js
export default class PostsLayout extends React.Component {
render() {
const {summary, stringTime, user} = this.props;
return (
<TouchableOpacity
style={styles.container}
onPress={this.props.onPress}
>
<PostsUser user={user}/>
<PostsSummary summary={summary}/>
<PostsDate time={stringTime}/>
</TouchableOpacity>
)
}
}
FlatListLayout.js
export default class FlatListLayout extends React.Component {
render() {
return (
<ScrollView >
<FlatList
data={this.props.data}
renderItem={({item}) => <PostsLayout {...item} onPress={this.props.onPress}/>}
/>
</ScrollView>
)
}
}
ScreenLayout.js
export default class ScreenLayout extends React.Component {
state = {
posts: []
}
db = firebase.firestore()
path = this.db.collection('usersData').doc(firebase.auth().currentUser.uid).collection("posts")
onCollectionUpdate = (querySnapshot) => {
const posts = [];
querySnapshot.forEach((doc) => {
const {summary, time, stringTime, user, userId} = doc.data();
posts.push({
key: doc.id, doc, summary,
time, stringTime, user, userId
});
});
this.setState({
posts
});
}
componentDidMount() {
const {currentUser} = firebase.auth();
this.setState({currentUser})
this.unsubscribe = this.path.onSnapshot(this.onCollectionUpdate)
}
componentWillUnmount() {
this.unsubscribe();
}
render() {
return (
<FlatListLayout
data={this.state.posts}
onPress={() => {console.log(this.state.posts[0].key)}}
/>
)
}
}
Thank you for reading this and please help :)
So the easiest fix would be send a function argument from the original press event in the child level.
For example, PostsLayout has the main onPress, so on this call just send back any data you need, each component will have specific data related to the component. As each react child is unique.
PostsLayout.js
export default class PostsLayout extends React.Component {
handleOnPress = () => {
const { onPress, index } = this.props;
if( typeof onPress === 'function') {
onPress(this.props, index); // here pass anything you want in the parent level, like even userm stringtime etc
}
}
render() {
const {summary, stringTime, user} = this.props;
return (
<TouchableOpacity
style={styles.container}
onPress={this.handleOnPress}
>
<PostsUser user={user}/>
<PostsSummary summary={summary}/>
<PostsDate time={stringTime}/>
</TouchableOpacity>
)
}
}
FlatListLayout.js
export default class FlatListLayout extends React.Component {
render() {
return (
<ScrollView >
<FlatList
data={this.props.data}
renderItem={({item, index }) => <PostsLayout {...item} index={index} onPress={this.props.onPress}/>}
/>
</ScrollView>
)
}
}
ScreenLayout.js
export default class ScreenLayout extends React.Component {
state = {
posts: []
}
db = firebase.firestore()
path = this.db.collection('usersData').doc(firebase.auth().currentUser.uid).collection("posts")
onCollectionUpdate = (querySnapshot) => {
const posts = [];
querySnapshot.forEach((doc) => {
const {summary, time, stringTime, user, userId} = doc.data();
posts.push({
key: doc.id, doc, summary,
time, stringTime, user, userId
});
});
this.setState({
posts
});
}
componentDidMount() {
const {currentUser} = firebase.auth();
this.setState({currentUser})
this.unsubscribe = this.path.onSnapshot(this.onCollectionUpdate)
}
componentWillUnmount() {
this.unsubscribe();
}
render() {
return (
<FlatListLayout
data={this.state.posts}
onPress={(data, index) => {console.log(data); console.log(this.state.posts[index].key)}}
/>
)
}
}
Let me know if this doesn't make any sense :)
In here I have two problems. First is I'm trying to fetch dome data from my api and then pass this data to modal upon tapping a button. I have tried to use "state" and then declare that state like;
constructor(props){
super(props)
this.state = {
tbl: [],
tbl_no: null,
}
}
fetchTblOccpd = async () => {
const response = await fetch('http://192.168.***.***:****/PndngVRoutes/Occupied/');
const json = await response.json();
this.setState({ tbl: json })
this.setState({ tbl_no: json })
}
render() {
return (
.....
<PndModal
modalVisible = { this.state.modalVisible }
setModalVisible = { (vis) => { this.setState({ modalVisible: vis }) }}
tbl_no = { this.state.tbl_no }
/>
)
}
But this didn't work. I'm targeting to fetch a data and pass it to my Modal.
Sample
My Second question is after passing some data to Modal, I'm targeting to navigate to another screen/view from my modal.
here's my code
export default class PndModal extends Component {
constructor(props) {
super(props);
this.state = {
pnd_Data: [],
modalVisible: props.modalVisible,
};
}
componentWillReceiveProps(nextProps) {
this.setState({
modalVisible: nextProps.modalVisible,
tbl_no: nextProps.tbl_no, //This is the data I'm trying to pass.
})
}
fetchOrdered = async () => {
const response = await fetch("http://192.168.254.***:****/PndngVRoutes/PendingView/" + this.state.tbl_no);
const json = await response.json();
this.setState({ pnd_Data: json })
}
componentDidMount() {
this.fetchOrdered();
}
_onPressItem = () => {
this.setState({
modalVisible: false,
});
}
render() {
return (
<Modal>
<View>
<View>
<View>
<Text>Table No: { this.state.tbl_no }</Text>
<FlatList
data = {this.state.pnd_Data}
numColumns = { 2 }
keyExtractor={(item, index) => index.toString()}
renderItem = {({ item }) =>
<View>
<Text>{ item.menu_name }</Text>
</View>
}
/>
<TouchableOpacity
onPress = { () => this.props.navigation.navigate('pend') }> // This is my navigation code
<Text>Add Order</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
)
}
}
Hello Am not too use to react native but i think is must be the same as react , for the solution to your problem , i think you should use reusable component . then create then pass your data as a props.
Here is an example in react.
//My reusable component
const Modal=(props) =>{
return (
<div>
{props.data}
</div>
);
}
}
Then you call your reusable component then pass the results from the api to it.
<Modal
data ={this.state.pnd_Data}
/>
for the second question you can just add link that will navigate you .... there will be no problem for that .
you can read about reusable component here
https://itnext.io/react-component-class-vs-stateless-component-e3797c7d23ab
Working on displaying data in my Firebase Cloud Firestore, but I get an error when in my code. Can't understand what the issue is?
I have tried using export default in a new file, instead of using class for my RootStack, but I get an error when I try to do that as well.
export default class App extends React.Component {
render() {
return <RootStack />;
}
}
const RootStack = createStackNavigator(
{
Auth: {
screen: Auth, navigationOptions: { header: null },
},
Login: {
screen: Login, navigationOptions: { header: null },
},
Home: {
screen: Home, navigationOptions: { header: null },
},
}
);
class Home extends React.Component {
constructor(props){
super(props);
this.state = ({
todoTasks: []
})
this.ref = firestore.collection("tips");
}
componentDidMount() {
this.unsubscribe = this.ref.onSnapshot((querySnapshot) => {
const todos = [];
querySnapshot.forEach((doc) => {
todos.push({
tips: doc.data().tips
})
})
this.setState({
todoTask: todos
})
})
}
render() {
return (
<View>
<Flatlist
data={this.state.todoTask}
renderItem={({ item, index }) => {
return(
<Text>{item.tips}</Text>)
}}
>
</Flatlist>
</View>
)
}
}