how to update state according to id? - reactjs

I have a touchableopacity on each card where I want to setstate of expand to true, but I want to do it according to the id, so that state of only one changes, any idea how to do it using map()?
My code:
import React, {useState, useEffect} from 'react';
import {
SafeAreaView,
Text,
Image,
ScrollView,
TouchableOpacity,
View,
} from 'react-native';
import axios from 'axios';
import {ROOT} from '../../../../ApiUrl';
import Icon from 'react-native-vector-icons/FontAwesome';
export default function VaccinationListScreen(props) {
const [expand, setExpand] = useState(false);
const [data, setData] = useState('');
let id = props.route.params.id;
const getData = () => {
let url = `some url`;
console.log('bbb');
axios
.get(url)
.then(function (res) {
console.log(res.data.content);
setData(res.data.content);
})
.catch(function (err) {
console.log(err);
});
};
useEffect(() => {
getData();
}, []);
return (
<SafeAreaView>
<ScrollView>
<TouchableOpacity style={{padding: 10}} onPress={()=>setExpand(true)}>
{data != undefined &&
data != null &&
data.map((item) => {
return (
<View
style={{
padding: 10,
backgroundColor: '#fff',
elevation: 3,
margin: '2%',
borderRadius: 5,
}}
key={item.id}>
<View style={{alignItems: 'flex-end'}}>
<Text style={{color: 'grey', fontSize: 12}}>
{item.display_date}
</Text>
</View>
<View style={{flexDirection: 'row'}}>
<View>
<Image
source={require('../../assets/atbirth.jpg')}
style={{height: 40, width: 50}}
resizeMode="contain"
/>
</View>
<View style={{flex: 1}}>
<View style={{flexDirection: 'row', flex: 1}}>
<Text
key={item.id}
style={{
fontFamily: 'Roboto',
fontSize: 18,
fontWeight: 'bold',
}}>
{item.name}
</Text>
</View>
<View style={{flexDirection: 'row', width: '30%'}}>
{item.vaccine_list.map((i) => {
return (
<View style={{flexDirection: 'row'}}>
<Text
numberOfLines={1}
ellipsizeMode="tail"
style={{fontFamily: 'Roboto', fontSize: 15}}>
{i.name},
</Text>
</View>
);
})}
</View>
</View>
</View>
<View style={{alignItems: 'flex-end', marginTop: '1%'}}>
<View style={{flexDirection: 'row'}}>
<Text
style={{
color: 'red',
fontSize: 14,
fontWeight: 'bold',
}}>
{item.child_vacc_status.text}
</Text>
<Icon
name="chevron-up"
color="red"
size={12}
style={{marginTop: '1%', marginLeft: '1%'}}
/>
</View>
</View>
</View>
);
})}
</TouchableOpacity>
</ScrollView>
</SafeAreaView>
);
}
Any suggestions would be great, do let mw know if anything else is required for better understanding

As i review your code <TouchableOpacity> wraps all of your cards at once not on each card set. If you implement your code that way if it's not impossible it will be difficult for you to reference each cards id and set the state of expand to true according to cards id.
My suggestion is to include <TouchableOpacity> to map() function nest so that it will be easy to reference each cards function.
I reproduce this specific problem and implement a solution in which I was able to set the state of expand to true according to each cards id.
You may click the sandbox link to see a demonstration.
https://codesandbox.io/s/accordingtoid-4px1w
Code in Sandbox:
import React, { useState, useEffect } from "react";
import {
SafeAreaView,
Text,
Image,
TouchableOpacity,
View
} from "react-native";
// import axios from 'axios';
// import {ROOT} from '../../../../ApiUrl';
// import Icon from "react-native-vector-icons/FontAwesome";
export default function VaccinationListScreen(props) {
const [expand, setExpand] = useState({});
const [data, setData] = useState([]);
// let id = props.route.params.id;
// const getData = () => {
// let url = `some url`;
// console.log('bbb');
// axios
// .get(url)
// .then(function (res) {
// console.log(res.data.content);
// setData(res.data.content);
// })
// .catch(function (err) {
// console.log(err);
// });
// };
// useEffect(() => {
// getData();
// }, []);
useEffect(() => {
// In order to simulate and reproduce the problem
// Assume that these are the data that you fetch from an API
const dataContent = [
{
id: 1,
name: "At Birth",
display_date: "02 May - 08 May 16",
vaccine_list: [
{ name: "BCG" },
{ name: "Hepatitis B" },
{ name: "OPV 0" }
],
child_vacc_status: { text: "Missed" }
},
{
id: 2,
name: "At 6 Weeks",
display_date: "02 May - 08 May 16",
vaccine_list: [
{ name: "IPV" },
{ name: "PCV" },
{ name: "Hepatitis b" },
{ name: "DTP" },
{ name: "HiB" },
{ name: "Rotavirus" }
],
child_vacc_status: { text: "Missed" }
}
];
setData(dataContent);
}, []);
function handleOnPress(id) {
setExpand((prev) => {
let toggleId;
if (prev[id]) {
toggleId = { [id]: false };
} else {
toggleId = { [id]: true };
}
return { ...toggleId };
});
}
useEffect(() => {
console.log(expand); // check console to see the value
}, [expand]);
return (
<SafeAreaView>
{data !== undefined &&
data !== null &&
data.map((item) => {
return (
<TouchableOpacity
key={item.id}
style={{
padding: 10
}}
onPress={() => handleOnPress(item.id)}
>
<View
style={{
padding: 10,
backgroundColor: expand[item.id] ? "lightgrey" : "#fff",
elevation: 3,
margin: "2%",
borderRadius: 5
}}
>
<View style={{ alignItems: "flex-end" }}>
<Text style={{ color: "grey", fontSize: 12 }}>
{item.display_date}
</Text>
</View>
<View style={{ flexDirection: "row" }}>
<View>
<Image
// source={require('../../assets/atbirth.jpg')}
style={{ height: 40, width: 50 }}
resizeMode="contain"
/>
</View>
<View style={{ flex: 1 }}>
<View style={{ flexDirection: "row", flex: 1 }}>
<Text
key={item.id}
style={{
fontFamily: "Roboto",
fontSize: 18,
fontWeight: "bold"
}}
>
{item.name}
</Text>
</View>
<View style={{ flexDirection: "row", width: "30%" }}>
{item.vaccine_list.map((item, i) => {
return (
<View key={i} style={{ flexDirection: "row" }}>
<Text
numberOfLines={1}
ellipsizeMode="tail"
style={{ fontFamily: "Roboto", fontSize: 15 }}
>
{item.name},
</Text>
</View>
);
})}
</View>
</View>
</View>
<View style={{ alignItems: "flex-end", marginTop: "1%" }}>
<View style={{ flexDirection: "row" }}>
<Text
style={{
color: "red",
fontSize: 14,
fontWeight: "bold"
}}
>
{item.child_vacc_status.text}
</Text>
</View>
</View>
</View>
</TouchableOpacity>
);
})}
</SafeAreaView>
);
}

I haven't tested the code to work correctly, but you could try something similar. You could create a separate component for the items and set a status for each of them.
export default function VaccinationListScreen(props) {
const [expand, setExpand] = useState(false);
const [data, setData] = useState("");
const VaccinationListItem = (item) => {
const [expand, setExpand] = useState(false);
return (
<TouchableOpacity style={{ padding: 10 }} onPress={() => setExpand(true)}>
<View
style={{
padding: 10,
backgroundColor: "#fff",
elevation: 3,
margin: "2%",
borderRadius: 5,
}}
key={item.id}
>
<View style={{ alignItems: "flex-end" }}>
<Text style={{ color: "grey", fontSize: 12 }}>
{item.display_date}
</Text>
</View>
<View style={{ flexDirection: "row" }}>
<View>
<Image
source={require("../../assets/atbirth.jpg")}
style={{ height: 40, width: 50 }}
resizeMode="contain"
/>
</View>
<View style={{ flex: 1 }}>
<View style={{ flexDirection: "row", flex: 1 }}>
<Text
key={item.id}
style={{
fontFamily: "Roboto",
fontSize: 18,
fontWeight: "bold",
}}
>
{item.name}
</Text>
</View>
<View style={{ flexDirection: "row", width: "30%" }}>
{item.vaccine_list.map((i) => {
return (
<View style={{ flexDirection: "row" }}>
<Text
numberOfLines={1}
ellipsizeMode="tail"
style={{ fontFamily: "Roboto", fontSize: 15 }}
>
{i.name},
</Text>
</View>
);
})}
</View>
</View>
</View>
<View style={{ alignItems: "flex-end", marginTop: "1%" }}>
<View style={{ flexDirection: "row" }}>
<Text
style={{
color: "red",
fontSize: 14,
fontWeight: "bold",
}}
>
{item.child_vacc_status.text}
</Text>
<Icon
name="chevron-up"
color="red"
size={12}
style={{ marginTop: "1%", marginLeft: "1%" }}
/>
</View>
</View>
</View>
</TouchableOpacity>
);
};
return (
<SafeAreaView>
<ScrollView>
{data != undefined &&
data != null &&
data.map((item) => {
VaccinationListItem(item);
})}
</ScrollView>
</SafeAreaView>
);
}

Generally if you want to toggle any single element you should store its id in expand (instead of a boolean), and simply check when rendering the array if any specific element's id matches, i.e. element.id === expand. When any new element is touched, pop its id in there, if the id is already there, set to null to collapse.
export default function VaccinationListScreen(props) {
const [expandId, setExpandId] = useState(null); // <-- stores null or id, initially null
...
// Create curried handler to set/toggle expand id
const expandHandler = (id) => () =>
setExpandId((oldId) => (oldId === id ? null : id));
return (
<SafeAreaView>
<ScrollView>
{data &&
data.map((item) => {
return (
<View
...
key={item.id}
>
<TouchableOpacity
style={{ padding: 10 }}
onPress={expandHandler(item.id)} // <-- attach callback and pass id
>
...
</TouchableOpacity>
{item.id === expandId && ( // <-- check if id match expand id
<ExpandComponent />
)}
</View>
);
})}
</ScrollView>
</SafeAreaView>
);
}

Related

can't write on my textInput inside my flatlist

I try to do a profil update with a flatlist to catch all my value and attribute. but when i want to write something new is not working. i tried to take off my placeholder and my default value with my actual value, then write something but i have the same problem.
const Item = ({ attribute, value, item }) => {
return (
<View
key={item}
style={{
flex: 1,
flexDirection: "column",
marginBottom: 20,
paddingLeft: 10,
}}>
<View
style={{
flexDirection: "row",
flex: 1,
alignItems: "center",
marginBottom: 5,
}}>
<View style={{ marginRight: 10 }}>
<Feather
onPress={() => {
setOnEdit(true);
}}
name="edit"
size={24}
color="#8E8E8E"
/>
</View>
<Text style={{ color: "#FF6B35", fontWeight: "bold" }}>
{attribute}
</Text>
</View>
<View style={{ flex: 1 }}>
<View style={{ flex: 1 }}>
{onEdite ? (
<TextInput
defaultValue={value}
placeholder={value}
placeholderTextColor={"black"}
onChangeText={(text) => {
createHandler(text, attribute);
}}
/>
) : (
<Text style={{ color: "#8E8E8E" }}>{value}</Text>
)}
</View>
</View>
</View>
)
);
};
this is also my createHandler method of all my textInput
const createHandler = (text, fieldName) => {
console.log(text, fieldName);
setForm((oldValue) => {
return {
...oldValue,
[fieldName]: text,
};
});
};

set state required double click

I have a useState hook that stores if a menu should be shown or not, in my jsx render I have a touchableOpacity that when I change it, it should update my state and show the menu, but the state does not update unless I give it click more than once to the touchable.
this error happens with the expenseActivitie state, when updating it within the showExpenses function.
Screen:
import React, { useContext, useEffect, useState } from 'react'
import { Dimensions, Text, TouchableOpacity, View } from 'react-native'
import { StackScreenProps } from '#react-navigation/stack';
import { RootStackParams } from '../../navigator/Navigator';
import { commonStyles } from '../../styles/commonStyles';
import { ThemeContext } from '../../contexts/theme/ThemeContext';
import LinearGradient from 'react-native-linear-gradient';
import { FontAwesomeIcon } from '#fortawesome/react-native-fontawesome';
import { faExclamationCircle, faFilter } from '#fortawesome/free-solid-svg-icons';
import { ExpenseActivitiesRQ } from '../../interfaces/viatics/ExpenseActivitiesRQ';
import { useActivities } from '../../hooks/viatics/useActivities';
import { AuthContext } from '../../contexts/auth/AuthContext';
import { FlatList, ScrollView } from 'react-native-gesture-handler';
import { GActivities } from '../../interfaces/viatics/GActivities';
import Icon from 'react-native-vector-icons/Ionicons'
import Moment from 'moment';
import { setStateActivity } from '../../helpers/viatics/setStateActivity';
import { setStateColor } from '../../helpers/viatics/setStateColor';
import { ExpensesScreen } from './ExpensesScreen';
import { ActivityIndicator } from 'react-native';
import { Col, Grid, Row } from 'react-native-easy-grid';
import { activitiesStyles } from '../../styles/activitiesStyles';
import { MenuActivity } from '../../components/viatics/menuActivity';
import { GExpenses } from '../../interfaces/viatics/GExpenses';
interface Props extends StackScreenProps<RootStackParams, 'ActivitiesListScreen'>{};
export const ActivitiesListScreen = ( { route, navigation }: Props ) => {
const { userData } = useContext( AuthContext );
const request: ExpenseActivitiesRQ = {
IDUser: userData.IDUser,
IDEntity: userData.IDEntityDefault,
excludeImages: true
};
const type = route.params.type;
const { loading, activitiesList } = useActivities( type, request );
const { theme: { colors, secondary, buttonText } } = useContext( ThemeContext );
const [expenseActivitie, setExpenseActivitie] = useState({
showExpense: false,
currentIndex: -1
});
const [menus, setMenus] = useState({
menuExpense: false,
menuActivity: false
});
const [currentExpense, setCurrentExpense] = useState({
menuExpense: false,
data: new GExpenses()
});
useEffect(() => {
switch( type ) {
case 'allActivities':
navigation.setOptions({
title: 'Actividades Generales'
});
break;
case 'pendingApprove':
navigation.setOptions({
title: 'Pendientes por Aprobar'
});
break;
case 'pendingLegalize':
navigation.setOptions({
title: 'Pendientes por Legalizar'
});
break;
default:
navigation.setOptions({
title: 'Activitidades'
});
break;
}
}, []);
const renderActivitieCard = ( activitie: GActivities, index: number ) => {
const bottomPadding: number = ( activitiesList.ListActivities.length === ( index + 1 ) && ( menus.menuActivity || menus.menuExpense ) ) ? 80 : 0;
return (
<>
<View style={{ paddingBottom: bottomPadding }}>
<View style={{ ...activitiesStyles.datesContainer, backgroundColor: colors.primary,}}>
<Text style={{ color: buttonText, fontSize: 12, marginLeft: 4 }}>
{ Moment(activitie.DateSta).format('DD/MMMM/YYYY') }
</Text>
<Icon
name="repeat"
color={ buttonText }
size={ 30 }
/>
<Text style={{ color: buttonText, fontSize: 12 }}>
{ Moment(activitie.DateEnd).format('DD/MMMM/YYYY') }
</Text>
<View style={{ ...activitiesStyles.activityState, backgroundColor: setStateColor(activitie.State) }}>
<Text style={{ textAlign: 'center', color: buttonText }}>{ setStateActivity(activitie.State) }</Text>
</View>
</View>
<View style={{ borderWidth: 2, marginBottom: 10, borderColor: colors.primary, borderBottomLeftRadius: 10, borderBottomRightRadius: 10 }}>
<View style={{ marginTop: 10, marginBottom: 5 }}>
<View style={{ ...activitiesStyles.dataContainer, }}>
<Text style={{color: colors.text, fontWeight: 'bold'}}>Pasajero: </Text>
<Text style={{color: colors.text}}>{ activitie.UserName }</Text>
</View>
<View style={{ ...activitiesStyles.dataContainer }}>
<Text style={{color: colors.text, fontWeight: 'bold'}}>Actividad: </Text>
<Text style={{color: colors.text}}>{ activitie.Description }</Text>
</View>
<View style={{ ...activitiesStyles.dataContainer }}>
<Text style={{color: colors.text, fontWeight: 'bold'}}>Gastos Registrados: </Text>
<Text style={{color: colors.text}}>{ activitie.countExpenses }</Text>
</View>
<View style={{ ...activitiesStyles.dataContainer }}>
<Text style={{color: colors.text, fontWeight: 'bold'}}>Registrado: </Text>
<Text style={{color: colors.text}}>{ activitie.totalExpense } de { activitie.Budget } </Text>
</View>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-around' }}>
<TouchableOpacity
onPress={ () => showExpenses(index) }
style={{
...commonStyles.entireButton,
}}>
<LinearGradient
colors={[colors.primary, secondary]}
style={ commonStyles.smallButton }
>
<Text style={[commonStyles.buttonText, {
color: buttonText
}]}> Ver Gastos </Text>
</LinearGradient>
</TouchableOpacity>
<TouchableOpacity
onPress={ () => navigation.navigate('RegisterExpensesScreen') }
style={{
...commonStyles.entireButton,
}}>
<LinearGradient
colors={[colors.primary, secondary]}
style={ commonStyles.smallButton }
>
<Text style={[commonStyles.buttonText, {
color: buttonText
}]}> Adicionar Gasto </Text>
</LinearGradient>
</TouchableOpacity>
<TouchableOpacity
onPress={ () => setMenus({
...menus,
menuActivity: !menus.menuActivity
})}
style={{
...commonStyles.entireButton,
}}>
<LinearGradient
colors={[colors.primary, secondary]}
style={ commonStyles.smallButton }
>
<Text style={[commonStyles.buttonText, {
color: buttonText
}]}> + Opciones </Text>
</LinearGradient>
</TouchableOpacity>
</View>
{ (expenseActivitie.showExpense === false && expenseActivitie.currentIndex === index ) &&
<ExpensesScreen currentActivity={ activitie } menus={ menus } parentCallBack= { handleCallBack } />
}
</View>
</View>
</View>
</>
)
}
const showExpenses = (index: number) => {
setExpenseActivitie({
...expenseActivitie,
showExpense: !expenseActivitie.showExpense,
currentIndex: index
})
}
const handleCallBack = (childData: GExpenses) => {
console.log('childData', childData);
setCurrentExpense({
...currentExpense,
data: childData,
menuExpense: true,
})
}
return (
<>
<View style={{
...commonStyles.container,
alignItems: 'stretch',
bottom: 50,
}}>
<Text style={{
...commonStyles.title,
color: colors.primary,
marginBottom: 10
}}>
Actividades de Gastos
</Text>
<View style={ commonStyles.rightButtonContainer }>
<TouchableOpacity
disabled={( activitiesList.ListActivities.length > 0) ? false : true }
onPress={ () => navigation.navigate('FilterActivitiesScreen') }
style={commonStyles.rightButton}>
<LinearGradient
colors={[colors.primary, secondary]}
style={{
...commonStyles.rightButton,
flexDirection: 'row'
}}
>
<FontAwesomeIcon
style={{
color: buttonText
}}
icon={ faFilter }
size={20} />
<Text style={[commonStyles.buttonText, {
color:'#fff'
}]}>Filtrar</Text>
</LinearGradient>
</TouchableOpacity>
</View>
{
!loading &&
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<ActivityIndicator
size="large"
animating={ true }
color={ colors.primary }
></ActivityIndicator>
</View>
}
{
( loading && activitiesList.ListActivities.length > 0 )
&&
<View style={{ marginTop: 10, flex: 1, width: '100%' }}>
<FlatList
data={ activitiesList.ListActivities }
keyExtractor={ (activie: GActivities) => activie.IDGroup }
renderItem={ ({ item, index }) => renderActivitieCard( item, index ) }
/>
</View>
}
{
( loading && activitiesList.ListActivities.length === 0 )
&&
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', }}>
<FontAwesomeIcon
icon={ faExclamationCircle }
color={ colors.primary }
size={ 100 }
/>
<Text style={{
...commonStyles.title,
fontSize: 25,
color: colors.primary,
marginBottom: 10
}}>
No se encontraron Actividades
</Text>
</View>
}
</View>
{ menus.menuActivity &&
<MenuActivity />
}
</>
)
}
I appreciate any help
setExpenseActivitie( prev => {
...prev,
showExpense: !expenseActivitie.showExpense,
currentIndex: index
})
Try to modify your showexpenses function to look this.

store.dispatch not updating props when called from outside of class

store.js
import AsyncStorage from "#react-native-community/async-storage";
import { createStore, applyMiddleware } from "redux";
import { persistStore, persistReducer } from "redux-persist";
import { createLogger } from "redux-logger";
import thunk from "redux-thunk";
import reducers from "../reducers";
const logger = createLogger({
// ...options
});
const persistedReducer = persistReducer(persistConfig, reducers);
export default () => {
let store = createStore(persistedReducer, {}, applyMiddleware(thunk, logger));
let persistor = persistStore(store);
return { store, persistor };
};
PathexploredTab.js
import * as React from "react";
import {
View,
StyleSheet,
Text,
Dimensions,
TouchableOpacity,
Alert,
Platform,
Image
} from "react-native";
import { TabView, SceneMap, TabBar } from "react-native-tab-view";
import { Config } from "#common";
import { connect } from "react-redux";
import { compose } from "redux";
import { Dropdown } from "react-native-material-dropdown";
import { Field, reduxForm } from "redux-form";
import { ScrollView } from "react-native-gesture-handler";
import { Actions } from "react-native-router-flux";
import Icon from "react-native-vector-icons/Feather";
import {
searchImmipaths,
isKeepData,
backToInitialState,
continueFromPrevious,
fetchDynamicFacts,
pathExplorerTutorial
} from "../actions/path.actions";
import { checkConnection } from "../service/checkConnection";
import Loader from "./Loader";
import { colors, normalize, family, Images } from "#common";
import ResponsiveImage from 'react-native-responsive-image';
import { RFValue } from "react-native-responsive-fontsize";
import RNPicker from "rn-modal-picker";
import * as Animatable from 'react-native-animatable';
import UserinfoPopUp from "./../pages/UserinfoPopUp";
import { updateUserDetails, getUserDetails } from "../actions/auth.actions";
import AsyncStorage from "#react-native-community/async-storage";
import { copilot, walkthroughable, CopilotStep } from 'react-native-copilot';
import { StepNumberComponent } from "./../pages/newProfileScreen";
import persist from "./../config/store";
import Reactotron from 'reactotron-react-native'
const WalkthroughableImage = walkthroughable(Image);
const WalkthroughableText = walkthroughable(Text);
const WalkthroughableView = walkthroughable(View);
const WalkthroughableTouch = walkthroughable(TouchableOpacity);
const persistStore = persist();
const TooltipComponent = ({
isFirstStep,
isLastStep,
handleNext,
handlePrev,
handleStop,
labels,
currentStep,
}) => {
const handleDiscardTutorial = () => {
Alert.alert(
'',
'are you sure you don’t want a tutorial on how to use the app?',
[
{
text: 'yes',
onPress: () => {AsyncStorage.setItem('DontShowTutorial', JSON.stringify(true)), handleStop()}
},
{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel'
},
],
{ cancelable: false }
);
}
return (
<View style={styles.tooltipContainer}>
<Text testID="stepDescription" style={styles.tooltipText}>{currentStep.text}</Text>
<View style={[styles.bottomBar]}>
{
!isFirstStep ?
<TouchableOpacity style={styles.toolTipButton} onPress={handlePrev}>
<Text style={styles.toolTipButtonText}>{'Previous'}</Text>
</TouchableOpacity>
: null
}
{
!isLastStep ?
<TouchableOpacity style={styles.toolTipButton} onPress={handleNext}>
<Text style={styles.toolTipButtonText}>{'Next'}</Text>
</TouchableOpacity> :
<TouchableOpacity style={styles.toolTipButton} onPress={handleStop}>
<Text style={styles.toolTipButtonText}>{'Finish'}</Text>
</TouchableOpacity>
}
<TouchableOpacity onPress={() => persistStore.store.dispatch(pathExplorerTutorial('bbv'))}>
<Text style={styles.toolTipButtonText}>Go</Text>
</TouchableOpacity>
<TouchableOpacity onPress={handleDiscardTutorial}>
<Text style={styles.toolTipButtonText}>Do not show tutorial</Text>
</TouchableOpacity>
</View>
</View>
);
}
const window = Dimensions.get("window");
var width = window.width;
var height = window.height;
var immigrationInterst = [];
var countryIntrest = [];
let countryIntrestNow = [];
var FirstRoute = () => <View style={[{ height: height }]} />;
let disableButton = false;
var lastSearchedCountries = [];
var SecondRoute = () => <View style={[{ height: height }]} />;
class PathexploredTab extends React.Component {
constructor(props) {
super(props);
this.imageMap = ['', Images.studyImage, Images.workImage, Images.residencyImage, Images.tourismImage];
this.state = {
isloading: false,
buttonone: false,
immibut1: false,
immibut2: false,
immibut3: false,
immibut4: false,
userInfoPopUpVisible: false,
countrybut1: false,
countrybut2: false,
countrybut3: false,
countrybut4: false,
filedsToShow: [],
countrybut5: false,
countrybut6: false,
selectedval: "Select the Country",
index: 0,
routes: [
{ key: "first", title: "Select Goals" },
{ key: "second", title: "Select Countries" }
],
checkconnection: false,
errorMessage: "",
isItemSelected: true,
currentlySelectedItemIndex: -1,
isItemChecked: true,
checkboxData: ""
};
}
componentDidUpdate = (nextProps) => {
Reactotron.log('=====', nextProps.userPressedGo)
}
componentWillReceiveProps = (nextProps) => {
}
componentWillMount = async() => {
const {
getUser: { userDetails },
authData: { token }
} = this.props;
this.props.dispatch(getUserDetails(userDetails.userid, token))
}
componentDidMount() {
setTimeout(() => {
this.props.start();
}, 1000);
immigrationInterst = [];
countryIntrest = [];
countryIntrestNow = [];
const {
getUser: { userDetails }
} = this.props;
}
callProceed = () => {
const {
isItemSelected,
currentlySelectedItemIndex,
isItemChecked
} = this.state;
if (isItemSelected) {
Alert.alert("Immigreat", "Please select any goal");
return;
}
const lastGoal = this.props.immigationInterest[0]
//This is a bit of a hacky fix but it works.
let allPrevCountriesFound = lastSearchedCountries.every(ai => countryIntrestNow.includes(ai))
&& (lastSearchedCountries.length == countryIntrestNow.length);
//We want to clear and search when:
//a) There is no exploration id
//b) Even if there is an exploration id but the lastGoal or last countries dont match
//Note: We make one exception for if exploration id exists but the lastSearchedCountries is just an empty list
let noExplorationId = (this.props.explorationId === "");
let countryGoalDontMatch = (lastGoal != currentlySelectedItemIndex || !allPrevCountriesFound);
let isProceedException = (lastSearchedCountries.length == 0 && !noExplorationId);
noExplorationId || (!noExplorationId && countryGoalDontMatch && !isProceedException)
?
this.clearAndSearch()
: Alert.alert(
"Immigreat",
"Previous exploration found. Would you like to continue?",
[
{
text: "START FROM BEGINNING",
onPress: () => {
this.props.dispatch(continueFromPrevious(0));
this.props.dispatch(backToInitialState());
this.props.dispatch(isKeepData(false));
this._searchData();
},
style: "cancel"
},
{
text: "CONTINUE",
onPress: () => {
lastSearchedCountries = [...countryIntrest];
this.props.dispatch(isKeepData(true));
this.props.didTapOnSearch();
}
},
{
text: "Cancel",
onPress: () => console.log("Canceled"),
style: "cancel"
}
],
{ cancelable: false }
);
}
_onPressBackButton = () => {
this.setState(
{
isItemSelected: true,
currentlySelectedItemIndex: -1,
isItemChecked: false
},
() => {
setTimeout(() => {
this.intialLoadValues();
//this.setState({ isItemSelected: true });
}, 0);
}
);
}
extraOptionsRefresh() {
const { currentlySelectedItemIndex, isItemChecked } = this.state;
this.setState({ isItemChecked: !isItemChecked })
switch (currentlySelectedItemIndex) {
case 1:
this.setState({checkBoxData:
"Do you want to explore options you may have after your studies?"});
break;
case 2:
this.setState({checkBoxData:
"Do you want to explore other goal options (such as studies) that can lead to work options?"});
break;
case 3:
this.setState({checkBoxData:
"Do you want to explore other goal options (such as studies or work) that could lead to permanent residency in the future?"});
break;
case -1:
this.setState({checkBoxData: ""});
break;
}
}
intialLoadValues() {
const { currentlySelectedItemIndex, isItemChecked } = this.state;
/*var checkBoxData = "";
switch (currentlySelectedItemIndex) {
case 1:
checkBoxData =
"Do you want to explore options you may have after your studies?";
break;
case 2:
checkBoxData = "Do you want to explore other goal options (such as studies) that can lead to work options?";
break;
case 3:
checkBoxData =
"Do you want to explore other goal options (such as studies or work) that could lead to permanent residency in the future?";
break;
case 4:
checkBoxData = "";
break;
}*/
FirstRoute = () => (
<ScrollView style={{ flex: 1, backgroundColor: "white" }}>
<Animatable.View animation="fadeIn" duration={1200} style={{ flex: 1 }}>
<View
style={{
backgroundColor: "#DBDDDF",
alignItems: "center",
justifyContent: "center",
flex: 1
}}
>
<View style={{ padding: 20 }}>
<Text
style={{
textAlign: "center",
fontFamily: "SourceSansPro-Semibold",
color: "#2C393F",
fontSize: RFValue(12)
}}
>
Select the Immigration goal that you would be interested in
exploring
</Text>
<Text
style={{
textAlign: "center",
color: "#008BC7",
fontFamily: "SourceSansPro-Regular",
fontSize: RFValue(10)
}}
>
You can select/deselect ONLY one goal at a time by clicking the buttons. This is so we can help you hone your search!
</Text>
</View>
</View>
{(this.state.isItemSelected && this.state.currentlySelectedItemIndex < 0) ? (
<View style={{ marginTop: 30 }}>
{/*<Animatable.View animation="fadeIn" duration={1200} style={{ flexGrow: 1, justifyContent: 'center', alignItems: 'center', flexDirection: 'row' }}>*/}
<View style={styles.custombuttonView}>
<View style={{ width: "50%" }}>
<CopilotStep text="Select Your goals" order={1} name="study">
<WalkthroughableTouch
testID={`${Config.immigerat[0].code + 'button'}`}
onPress={() =>
this._immigreateIntrest(Config.immigerat[0].code)
}
style={
this.state.immibut1
? styles.selectedbutton
: styles.buttonstyleview
}
>
<WalkthroughableText
style={
this.state.immibut1
? styles.selectedbuttontext
: styles.buttonstyletext
}
>
{Config.immigerat[0].value}
</WalkthroughableText>
</WalkthroughableTouch>
</CopilotStep>
</View>
<View style={{ width: "50%" }}>
<TouchableOpacity
testID={`${Config.immigerat[1].code + 'button'}`}
onPress={() =>
this._immigreateIntrest(Config.immigerat[1].code)
}
style={
this.state.immibut2
? styles.selectedbutton
: styles.buttonstyleview
}
>
<Text
style={
this.state.immibut2
? styles.selectedbuttontext
: styles.buttonstyletext
}
>
{Config.immigerat[1].value}
</Text>
</TouchableOpacity>
</View>
</View>
<View style={styles.custombuttonView}>
<View style={{ width: "50%" }}>
<TouchableOpacity
testID={`${Config.immigerat[2].code + 'button'}`}
onPress={() =>
this._immigreateIntrest(Config.immigerat[2].code)
}
style={
this.state.immibut3
? styles.selectedbutton
: styles.buttonstyleview
}
>
<Text
style={
this.state.immibut3
? styles.selectedbuttontext
: styles.buttonstyletext
}
>
{Config.immigerat[2].value}
</Text>
</TouchableOpacity>
</View>
<View style={{ width: "50%" }}>
<TouchableOpacity
testID={`${Config.immigerat[3].code + 'button'}`}
onPress={() =>
this._immigreateIntrest(Config.immigerat[3].code)
}
style={
this.state.immibut4
? styles.selectedbutton
: styles.buttonstyleview
}
>
<Text
style={
this.state.immibut4
? styles.selectedbuttontext
: styles.buttonstyletext
}
>
{Config.immigerat[3].value}
</Text>
</TouchableOpacity>
</View>
</View>
{/*</Animatable.View>*/}
</View>
) : (
<View style={{ flex: 0.75, marginTop: 30 }}>
{/*<Animatable.View animation="fadeIn" duration={1200}>*/}
<View style={{ flexDirection: 'row', alignContent: 'center' }}>
<TouchableOpacity testID='goBackButton'
onPress={this._onPressBackButton} style={{ padding: 10 }} >
<View style={{ width: 80 }}>
<Icon name="chevron-left" size={30} color="black" />
</View>
</TouchableOpacity>
{<TouchableOpacity
onPress={() => this._immigreateIntrest("null")}
style={[styles.selectedbutton, { width: "50%" }]}
>
<Text style={styles.selectedbuttontext}>
{Config.immigerat[this.state.currentlySelectedItemIndex - 1].value}
</Text>
</TouchableOpacity>}
</View>
{currentlySelectedItemIndex !== 4 && (
<View
style={{
borderWidth: 1,
borderRadius: 3,
borderColor: "rgba(110,110,110,0.4)",
flex: 1,
marginHorizontal: 10,
marginTop: 30,
flexDirection: "row"
}}
>
<TouchableOpacity
activeOpacity={0.8}
onPress={() => {
this.extraOptionsRefresh()
//setTimeout(() => {
//this.extraOptionsRefresh();
//this.intialLoadValues();
//this.setState({ isItemChecked: !isItemChecked });
//}, 100);
}
}
style={{
// flex: 0.35,
alignItems: "center",
justifyContent: "center",
marginLeft: 15
}}
hitSlop={{ top: 20, bottom: 20, left: 50, right: 50 }}
>
<View
style={[
styles.button,
{
backgroundColor: "white",
borderColor: "rgba(110,110,110,0.4)",
borderWidth: 1,
borderRadius: 2,
width: 20,
height: 20
}
]}
>
{this.state.isItemChecked ? (
<Icon name={"check"} color={colors.LIGHT_BLUE} size={15} />
) : null}
</View>
</TouchableOpacity>
<Text
style={{
flex: 1,
marginVertical: 10,
marginLeft: 10,
fontFamily: "SourceSansPro-Bold",
color: "#242424",
fontSize: RFValue(12)
}}
>
{this.state.checkBoxData}
</Text>
</View>
)}
{(!this.state.isItemSelected && this.state.currentlySelectedItemIndex > 0) &&
<Animatable.View animation="fadeIn" duration={1200} style={{ flexGrow: 1, justifyContent: 'center', alignItems: 'center', flexDirection: 'row' }}>
<ResponsiveImage source={this.imageMap[this.state.currentlySelectedItemIndex]} initWidth="270" initHeight="220" />
</Animatable.View>
}
</View>
)}
<View>
<TouchableOpacity
testID='searchButton'
onPress={() => !disableButton && this.showAlert1()}
style={{
width: 130,
justifyContent: "center",
backgroundColor: colors.LIGHT_BLUE,
borderRadius: 100,
padding: 10,
alignSelf: "center",
marginTop: height > 700 ? 60 : 40,
marginBottom: 20
}}
>
<Text
style={{
textAlign: "center",
color: "#fff",
fontFamily: "SourceSansPro-Regular"
}}
>
Search
</Text>
</TouchableOpacity>
</View>
</Animatable.View>
</ScrollView>
);
SecondRoute = () => (
<ScrollView style={{ flex: 1, backgroundColor: "white" }}>
<View style={{ backgroundColor: "white" }}>
<View
style={{
alignSelf: "center",
justifyContent: "center",
width: width
}}
>
<View style={{ margin: 20, alignSelf: "center" }}>
<Text
style={{
textAlign: "center",
fontFamily: "SourceSansPro-Semibold",
color: "#2C393F",
fontSize: 15
}}
>
Select all countries you are keen to explore
</Text>
<Text
style={{
textAlign: "center",
color: "rgba(44, 57, 63,0.6)",
marginTop: 20,
fontFamily: "SourceSansPro-Semibold"
}}
>
From:
</Text>
<View style={styles.loginView}>
<Field
name="selectcountry"
placeholder={this.state.selectedval}
component={this.renderDropdown}
data={Config.countries}
/>
</View>
<Text
style={{
textAlign: "center",
color: "rgba(44, 57, 63,0.6)",
marginTop: 20,
fontFamily: "SourceSansPro-Semibold"
}}
>
To:
</Text>
</View>
</View>
<View>
<View style={styles.custombuttonView}>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[0].value + 'interestButton'}`}
onPress={() =>
this._countryIntrest(Config.intrestcountry[0].code)
}
>
<Image
style={styles.countryIcon}
source={this.state.countrybut1
? Images.usa_selected
: Images.usa_unavailable}
/>
</TouchableOpacity>
</View>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[1].value + 'interestButton'}`}
>
<Image
style={styles.countryIcon}
source={this.state.countrybut2
? Images.canada_selected
: Images.canada_unavailable}
/>
</TouchableOpacity>
</View>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[2].value + 'interestButton'}`}
onPress={() =>
this._countryIntrest(Config.intrestcountry[2].code)
}
>
<Image
</TouchableOpacity>
</View>
</View>
<View style={styles.custombuttonView}>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[3].value + 'interestButton'}`}
onPress={() =>
this._countryIntrest(Config.intrestcountry[3].code)
}
>
<Image
/>
</TouchableOpacity>
</View>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[4].value + 'interestButton'}`}
onPress={() =>
this._countryIntrest(Config.intrestcountry[4].code)
}
>
<Image
</TouchableOpacity>
</View>
<View style={{ width: "33%" }}>
<TouchableOpacity
testID={`${Config.intrestcountry[5].value + 'interestButton'}`}
onPress={() =>
this._countryIntrest(Config.intrestcountry[5].code)
}
>
<Image
/>
</TouchableOpacity>
</View>
</View>
</View>
<View>
<TouchableOpacity
testID='countrySearchButton'
onPress={() => !disableButton && this.showAlert1()}
style={{
}}
>
<Text
>
Search
</Text>
</TouchableOpacity>
</View>
</View>
</ScrollView>
);
}
_countryIntrest(code) {
// alert(code);
var index = countryIntrest.indexOf(code);
var butstr = "countrybut" + code;
if (index == -1) {
countryIntrest.push(code);
countryIntrestNow.push(code);
this.setState({ [butstr]: true });
this.intialLoadValues();
} else {
countryIntrest.splice(index, 1);
countryIntrestNow.splice(index, 1);
this.setState({ [butstr]: false });
this.intialLoadValues();
}
}
_immigreateIntrest = async(code) => {
if(code === 4){
)
return;
}
const { isItemSelected } = this.state;
if (code === "null") {
);
} else {
await this.setState(
);
}
}
renderScene = ({ route }) => {
switch (route.key) {
case 'first':
case 'second':
default:
return null;
}
};
render() {
return (
<View style={{ flex: 1 }}>
{this.props.isLoading && (
<View
style={{
}}
>
<Loader />
</View>
)}
<TabView
removeClippedSubviews={Platform.OS === "android" ? true : false}
style={{
backgroundColor: this.state.index === 0 ? "#DBDDDF" : "white"
}}
navigationState={this.state}
removeClippedSubviews={Platform.OS === "android" ? true : false}
renderTabBar={props => (
<TabBar
}}
pass
getLabelText={({ route }) => route.title}
/>
)}
/>
<UserinfoPopUp
visible={this.state.userInfoPopUpVisible}
onClose={()=>this.setState({ userInfoPopUpVisible: false })}
userPopUpSubmit={this._userPopUpSubmit.bind(this)}
/>
</View>
);
}
}
mapStateToProps = state => ({
userPressedGo: state.pathReducer.getImmipathDetails.userPressedGo,
});
mapDispatchToProps = dispatch => ({
dispatch
});
export default compose(
connect(
mapStateToProps,
mapDispatchToProps
),
reduxForm({
form: "pathexplorertab"
// validate
})
)(copilot({
tooltipComponent: TooltipComponent,
stepNumberComponent: StepNumberComponent
})(PathexploredTab));
Pathexplorer.js contains Pathexplorer class in which there is an component called ToolTipComponent from which i am calling an action but the action isn't reflected in mapStateToProps. The reason i am forced to do this is that i am using a library called react-native-copilot in which i have a custom tooltip component from which i want to access the state
Problem in this event:
onPress={store.dispatch(action)}
should be:
onPress={()=>store.dispatch(action)}
By the way you can connect your functional component like class component:
export default connect(
mapStateToProps,
mapDispatchToProps
)
)(TooltipComponent)

how to set modal visible according to id?

I have a map() data each of which has touchableopacity that should set the state of modal visible to true, but am unable to do it.
Could anyone let me know a way to set the state according to id?
ParentComponent:
export default function ExpandedVaccineComponent(props) {
const {navigation} = props;
const [note, setNote] = useState({});
const [addNoteText, setAddNoteText] = useState('');
const [modalVisible, setModalVisible] = useState(false);
const [selectedItem,setSelectedItem]=useState(null);
const [demo, setDemo] = useState(false);
let id = props.id;
return (
<View
style={{
backgroundColor: '#fff',
elevation: 3,
margin: '2%',
borderRadius: 5,
}}>
<View style={{marginTop: '2%'}}>
{props.item.vaccine_list.map((i) => {
return (
<View style={{flex: 1}}>
<View style={{flexDirection: 'row'}}>
<TouchableOpacity onPress={() => setModalVisible(true)}>
<Icon name="calendar" size={15} />
</TouchableOpacity>
<View>
<Modal
animationType="fade"
transparent={true}
visible={modalVisible}>
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
borderRadius: 20,
}}>
<CalenderModal
item={props.item}
modalVisible={modalVisible}
item={i}
id={id}
/>
<View
style={{
flexDirection: 'row',
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
width: '72%',
}}>
<TouchableOpacity
style={{
flex: 1,
borderTopColor: '#C0C0C0',
borderTopWidth: 1,
borderRightColor: '#C0C0C0',
borderRightWidth: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 10,
}}
onPress={() => setModalVisible(!modalVisible)}>
<Text
style={{
fontFamily: 'Roboto',
fontSize: 17,
fontWeight: 'bold',
color: '#2D7AFA',
}}>
Cancel
</Text>
</TouchableOpacity>
<TouchableOpacity
style={{
flex: 1,
borderTopColor: '#C0C0C0',
borderTopWidth: 1,
borderLeftColor: '#C0C0C0',
borderLeftWidth: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 10,
}}>
<Text
style={{
fontFamily: 'Roboto',
fontSize: 17,
fontWeight: 'bold',
color: '#2D7AFA',
}}>
Save
</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
</View>
<View style={{marginLeft: '10%', width: '30%'}}>
<View>
<View style={{flexDirection: 'row'}}>
<Text
style={{
fontFamily: 'Roboto',
fontSize: 14,
color: '#000',
}}>
{i.name}
</Text>
<Text
style={{
fontFamily: 'Roboto',
color: '#000',
opacity: 0.5,
}}>
(Dose{i.dose}/3)
</Text>
</View>
<Text
numberOfLines={2}
ellipsizeMode="tail"
style={{
fontFamily: 'Roboto',
fontSize: 14,
lineHeight: 14,
color: '#000',
opacity: 0.5,
}}>
{i.protects_against}
</Text>
</View>
</View>
<View style={{marginLeft: '30%'}}>
<Text>{i.child_vacc_status.text}</Text>
<Text>16 Aug,2020</Text>
</View>
</View>
</View>
);
})}
</View>
</View>
);
}
CalenderModal component:
import React, {useState} from 'react';
import {View, Text, StyleSheet, TouchableOpacity, Image} from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
import DatePicker from 'react-native-datepicker';
import axios from 'axios';
import {ROOT} from '../../../ApiUrl';
export default function CalenderModal(props) {
const [date, setDate] = useState('2016-05-15');
const [vaccinatedOn, setVaccinatedOn] = useState(null);
const [reminder, setReminder] = useState(1);
const [toggle, setToggle] = useState(null);
const [modalVisible, setModalVisible] = useState(null);
const reminderSet = () => {
setReminder(6);
setToggle(6);
};
const vaccinationSet = () => {
setVaccinatedOn(1);
setToggle(1);
};
const data = props.item;
const id = props.id;
const SaveData = () => {
let url = `some url`;
axios({
method: 'POST',
url: url,
data: {
child_id: id,
event_date: date,
status: toggle,
vaccine_id: data.id,
},
headers: {
'content-type': 'application/json',
},
})
.then(function (res) {
console.log('RES', res);
if (res.data.code == 200) {
navigation.navigate('consultationHome', {res: res});
}
})
.catch(function (err) {
console.log('ERR', err);
});
};
return (
<View>
<View style={styles.modalView}>
<Text>{props.item.name}</Text>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
marginTop: '5%',
}}>
{reminder == 6 && toggle == 6 ? (
<TouchableOpacity style={{flexDirection: 'row'}}>
<Icon
name="circle"
size={17}
color="pink"
style={{marginTop: '2%', paddingRight: '1%'}}
/>
<Text
style={{
fontFamily: 'Roboto',
fontSize: 17,
color: '#000',
}}>
Set reminder
</Text>
</TouchableOpacity>
) : (
<TouchableOpacity
style={{flexDirection: 'row'}}
onPress={() => reminderSet()}>
<Icon
name="circle-o"
size={17}
color="#000"
style={{marginTop: '2%', paddingRight: '1%'}}
/>
<Text
style={{
fontFamily: 'Roboto',
fontSize: 17,
color: '#000',
}}>
Set reminder
</Text>
</TouchableOpacity>
)}
{vaccinatedOn == 1 && toggle == 1 ? (
<TouchableOpacity style={{flexDirection: 'row'}}>
<Icon
name="circle"
size={17}
color="pink"
style={{marginTop: '2%', paddingRight: '1%'}}
/>
<Text
style={{
fontFamily: 'Roboto',
fontSize: 17,
color: '#000',
}}>
Vaccinated on
</Text>
</TouchableOpacity>
) : (
<TouchableOpacity
style={{flexDirection: 'row'}}
onPress={() => vaccinationSet()}>
<Icon
name="circle-o"
size={17}
color="#000"
style={{marginTop: '2%', paddingRight: '1%'}}
/>
<Text
style={{
fontFamily: 'Roboto',
fontSize: 17,
color: '#000',
}}>
Vaccinated on
</Text>
</TouchableOpacity>
)}
</View>
<DatePicker
style={{width: 200, marginTop: '5%'}}
date={date}
mode="date"
placeholder="select date"
format="YYYY-MM-DD"
minDate="2016-05-01"
maxDate="2016-06-01"
confirmBtnText="Confirm"
cancelBtnText="Cancel"
customStyles={{
dateIcon: {
position: 'absolute',
left: 0,
top: 4,
marginLeft: 0,
},
dateInput: {
marginLeft: 36,
},
// ... You can check the source to find the other keys.
}}
onDateChange={(date) => {
setDate(date);
}}
/>
{console.log('DATE', date)}
</View>
</View>
);
}
const styles = StyleSheet.create({
modalView: {
backgroundColor: 'white',
padding: 20,
},
});
Any suggestion would be great, please let me know if anything else is required for better understanding.
you might want to try setting up your onPress similar to the RN documentation for TouchableOpacity (https://reactnative.dev/docs/touchableopacity.html you also may want to consider switching to Pressable for future proofing purposes). You can do
const onPress = () => setModalVisible(true);
<TouchableOpacity onPress={onPress}>

how to add keys in this project

im using react o nexpo xde and when i run the project i get a warning because my list doesnt hae keys, i want to know where and how to assing them, this is my code
import React, { Component } from 'react';
import { StyleSheet, Text, View,AppRegistry,Image,ActivityIndicator, FlatList,Navigator,TouchableHighlight, } from 'react-native';
import { StackNavigator } from 'react-navigation';
class Lista extends Component {
static navigationOptions = {
title: 'Lista',
}
constructor(props) {
super(props);
this.state = {
data:[]
};
}
load = async ()=>{
try{
let resp = await fetch('https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=fd829ddc49214efb935920463668608d')
let json = await resp.json()
this.setState({data:json.articles})
} catch (err) { console.log(err) }
}
componentDidMount(){this.load()}
render() {
return (
<View style={{ flex: 1}}>
<View style={{ flex:1,backgroundColor:'gray'}}>
<FlatList
data={this.state.data}
renderItem={({item}) => (
<TouchableHighlight onPress={() => this.props.navigation.navigate('Details', {item})}>
<View style={{ height:100,margin:15,backgroundColor:'skyblue', padding: 10, flexDirection: 'row'}}>
{item.urlToImage !== null &&
<Image source={{uri:item.urlToImage}} style={{width: 90, height: 80 }}/>
}
<View style={{ flex: 1 }}>
<Text style={{ textAlign: 'center',fontWeight: 'bold', fontSize: 18, color: 'white', flex:1, margin:10}}>{item.title}</Text>
<Text style={{ textAlign: 'right',fontWeight: 'bold', fontSize: 11, color: 'white'}}>{item.publishedAt}</Text>
</View>
</View>
</TouchableHighlight>
)}
/>
</View>
</View>
);
}
}
class DetailsScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
const { item } = navigation.state;
return {
title: item ? item.date : 'Details Screen',
}
};
render() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Image source={{uri:this.props.navigation.state.params.item.urlToImage}} style={{width: 90, height: 80 }}/>
<Text>{this.props.navigation.state.params.item.title}</Text>
<Text>{this.props.navigation.state.params.item.publishedAt}</Text>
</View>
);
}
}
const RootStack = StackNavigator(
{
Lista: {
screen: Lista,
},
Details: {
screen: DetailsScreen,
},
},
{
initialRouteName: 'Lista',
}
);
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
export default class App extends React.Component {
render() {
return <RootStack />;
}
}
i know it has to be something like, key={i} bu i hae tried in some ways and it doesnt work, im just learning react by myself so im a little confused here
ty so much
In your case you need to set up key to each child of <FlatList /> component. By react native docs recomended to use keyExtractor method defined in your component.
keyExtractor = (item, index) => index
render() {
return (
<View style={{ flex: 1}}>
<View style={{ flex:1,backgroundColor:'gray'}}>
<FlatList
data={this.state.data}
keyExtractor={this.keyExtractor}
renderItem={({item}) => (
<TouchableHighlight onPress={() => this.props.navigation.navigate('Details', {item})}>
<View style={{ height:100,margin:15,backgroundColor:'skyblue', padding: 10, flexDirection: 'row'}}>
{item.urlToImage !== null &&
<Image source={{uri:item.urlToImage}} style={{width: 90, height: 80 }}/>
}
<View style={{ flex: 1 }}>
<Text style= {{ textAlign: 'center',fontWeight: 'bold', fontSize: 18, color: 'white', flex:1, margin:10}}>{item.title}</Text>
<Text style= {{ textAlign: 'right',fontWeight: 'bold', fontSize: 11, color: 'white'}}>{item.publishedAt}</Text>
</View>
</View>
</TouchableHighlight>
)}
/>
</View>
</View>
);
}
I set just index of element as key, but you can set as you wont, but make sure it is unique. But using indexes is bad practice, it is not safe.

Resources