React Native FlatList: Toggle State Value - javascript

I am trying toggle text state from ACTIVE to INACTIVE (and vice versa) for each individual item in the FlatList. In the code below, the status toggles from true to false (and false to true) but the text in the app shows inactive and doesn't change.
import NameActionBar from '../components/NameActionBar';
export default class MasterScreen extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: [],
status: false,
};
}
componentDidMount() {
this.getFreelancerList();
}
//Calling API to get list
getFreelancerList() {
let self = this;
AsyncStorage.getItem('my_token').then((keyValue) => {
console.log('Master Screen (keyValue): ', keyValue); //Display key value
axios({
method: 'get',
url: Constants.API_URL + 'user_m/freelancer_list/',
responseType: 'json',
headers: {
'X-API-KEY': Constants.API_KEY,
'Authorization': keyValue,
},
})
.then(function (response) {
console.log('Response.Data: ===> ', response.data.data);
console.log('Response: ', response);
self.setState({
dataSource: response.data.data,
});
})
.catch(function (error) {
console.log('Error: ', error);
});
}, (error) => {
console.log('error error!', error) //Display error
});
}
//Show the list using FlatList
viewFreelancerList() {
const { dataSource } = this.state;
return (
<View>
{<FlatList
data={dataSource}
keyExtractor={({ id }, index) => index.toString()}
renderItem={({ item }) => {
return (
<View style={styles.containerFreelancer}>
<TouchableOpacity
style={{ flex: 1 }}
onPress={() => console.log(item.freelancer_name)}
>
<Text style={styles.textFreelancer}>{item.freelancer_name}</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
const newStatus = !this.state.status;
this.setState({
status: newStatus,
});
console.log('status: ', this.state.status);
}}
>
<Text>{this.state.status ? "ACTIVE" : "INACTIVE"}</Text>
</TouchableOpacity>
</View>
);
}}
/>}
</View>
);
}
render() {
return (
<>
<NameActionBar />
<ScrollView>
{this.viewFreelancerList()}
</ScrollView>
</>
);
}
}
My issues are:
How can I make the text toggle between active to inactive?
How can I make the text toggle separately for each item in the FlatList? for example: Item 1: 'ACTIVE', Item 2: 'INACTIVE' etc.
Any help would be appreciated as I am still new to learning React Native.
Screenshot of the app below:

You need to create a child component with its own state.
class FlatListComponent extends Component {
state = {
status: false
}
render() {
<View style={styles.containerFreelancer}>
<TouchableOpacity style={{ flex: 1 }} onPress={() => console.log(this.props.freelancer_name)}>
<Text style={styles.textFreelancer}>{this.props.freelancer_name}</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {
const newStatus = !this.state.status;
this.setState({
status: newStatus,
});
console.log('status: ', this.state.status);
}}
>
<Text>{this.state.status ? "ACTIVE" : "INACTIVE"}</Text>
</TouchableOpacity>
</View>
}
}
Then you just need to add it inside your renderItem method.
<FlatList
data={dataSource}
keyExtractor={({ id }, index) => index.toString()}
renderItem={({ item }) => <FlatListComponent {...item}/>
/>}
Here's a working example
I hope it helps ! Feel free to add comments if you're still stuck

Related

Disable TouchableOpacity after 5 clicks - React Native

I am pulling memes from an API and only want to show 5 memes therefore I tried to disable the touchableOpacity after certian number of clicks. Any ideas on how I can do that?
const link = 'https://meme-api.herokuapp.com/gimme'
class Meme extends React.Component {
constructor() {
super()
this.state = {
loading: false,
data: {
postLink: "sample data",
subreddit: "sample data",
title: "sample data",
url: 'https://poster.keepcalmandposters.com/8170567.jpg'
}
}
}
load = () => {
this.setState({ loading: true })
axios.get(link).then(res => {
this.setState({
data: res.data,
loading: false,
})
console.log(Object.keys(res.data))
})
}
This is where the "button" is
render() {
return (
<View>
<View style={styles.container}>
<View style={styles.imageView}>
<ProgressiveImage source={{ uri: this.state.data.url }} />
</View>
<TouchableOpacity style={styles.button}
onPress={() => {this.load()}} >
<Text style={styles.btnText}>Click to open a meme!</Text>
</TouchableOpacity>
</View>
<AnimatedLoader
visible={this.state.loading}
overlayColor="rgba(255,255,255,0.75)"
source={require("../loader.json")}
animationStyle={styles.lottie}
speed={1} />
</View>
);
}
};
I tried using state/setState for disabiling the button but nothing seems to work. I am okay with just disabiling the button but I tried it with two different pressHandlers, one for this.load() and another for disabling after a click but both of them does not work at the same time.
You need to create a counter state for the button and set the disable properties as well. Here's a simple example for it.
class Meme extends React.Component {
constructor() {
super();
this.state = {
count: 0
};
}
load = () => {
this.setState({ count++ })
// and others logic
}
render() {
return (
<TouchableOpacity onPress={() => {this.load()}} disabled = {this.state.count == 5 ? true : false}>
<Text>Click to open a meme!</Text>
</TouchableOpacity>
);
}
}
functional component example for this.
const Meme = () => {
const [count, setCount] = useState(0)
const loadForAPI = () => {
setCount(count => count + 1)
}
render() {
return (
<TouchableOpacity onPress={() => {loadForAPI()}} disabled = {count == 5 ? true : false}>
<Text>Click to open a meme!</Text>
</TouchableOpacity>
);
}
}
export default Meme;

Implementing searchbar into flatlist to search api data react native

I've implemented an searchbar as a header of a flatlist which displays my api data (the flatlist works fine ) but the searchbar don't work , i've tried several codes but stills not working
If someone can help me with this i'll appreciate it :)
My API displays an document which contains :
-Titre(String)
-Montant(Number)
I want to search by Titre .
Here's the last code that i've tried :
class listDépenses extends React.Component{
constructor() {
super();
this.state = {
refreshing: true,
dataSource: [],
Montant:'',
Titre:'',
modalVisible:false,
loading: false,
data: [],
error: null,
}
this.arrayholder = [];
}
renderItem = ({item}) => {
<View style={{flex:1}}>
<Text style={[globalStyles.sousTitre,{marginVertical:10,marginLeft:10}]}>{item.Titre}</Text>
<Text style={[globalStyles.sousTitre,
{marginVertical:10,marginLeft:40,textAlignVertical:'auto',opacity:0.8,fontWeight:'800'}]}>
{item.Montant}</Text>
</View>}
searchFilterFunction = text => {
const newData = this.arrayholder.filter(item => {
const itemData = `${item.Titre.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
renderHeader = () => {
return(
<SearchBar
placeholder="Tapez ici..."
onChangeText={text => this.searchFilterFunction(text)}
round="default"
lightTheme="default"
/>
)
}
this.setState({ data: newData });
};
async componentDidMount() {
await fetch ('http://192.168.1.10:8080/api/depenses',{
method:'get',
mode:'no-cors',
headers:{
'Accept':'application/json',
'Content-Type':'application/json'
}})
.then((response) => response.json())
.then((responseJson) => {
this.setState({
dataSource:responseJson,
data: responseJson.results,
loading: false,
})
this.arrayholder = responseJson.results;
})
.catch((error) =>{
console.log(error)
})}
render(){
return (
<View style={{flex:1}}>
<View style={{marginBottom:10}}></View>
<FlatList
data={this.state.dataSource}
renderItem={this.renderItem}
keyExtractor={(item, index) => index}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
/>
</View>
I've found the solution if anyone need it :
class listDépenses extends React.Component{
constructor(props) {
super(props);
this.delayValue = 8000;
this.state = {
search:'',
dataSource: [],
animatedValue: new Animated.Value(0),
Montant:'',
Titre:'',
isLoading:true,
modalVisible:false,
}
this.arrayholder=[]
}
componentDidMount() {
Animated.spring(this.state.animatedValue, {
toValue: 1,
tension: 20,
useNativeDriver: true
}).start();
return fetch('http://localhost:8080/api/depenses')
.then((response )=> response.json())
.then(responseJson => {
this.setState({
dataSource: responseJson,
isLoading: false,
},
function() {
this.arrayholder = responseJson;
});})
.catch(error => { console.error(error);});}
search = text => { console.log(text);
};
clear = () => { this.search.clear();
};
SearchFilterFunction(text) {
const newData = this.arrayholder.filter(function(item) { const itemData = item.Titre
? item.Titre.toUpperCase() :
''.toUpperCase();
const textData = text.toUpperCase(); return itemData.indexOf(textData) > -1;
});
this.setState({ dataSource: newData, search: text,
});
}
render(){
if (this.state.isLoading) { return (
<View style={{ flex: 1, paddingTop: 21 }}>
<ActivityIndicator />
</View>
);
}
return (
<View style={styles.container}>
<SearchBar
round="default"
lightTheme="default"
searchIcon={{ size: 25 }}
onChangeText={text => this.SearchFilterFunction(text)} onClear={text =>
this.SearchFilterFunction('')} placeholder="Tapez ici pour chercher..." value=
{this.state.search}
/>
<View style={{marginBottom:10}}></View>
<FlatList
data={this.state.dataSource}
renderItem={this.renderItem}
keyExtractor={(item, index) => index.toString()}
enableEmptySections={true} style={{ marginTop: 11 }}
ItemSeparatorComponent={this.renderSeparator}
/>
</View>

Display data from API Database with FlatList

export class Diet extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
fullData: [],
loading: false,
error: null,
query: "",
};
}
async componentDidMount() {
this.requestAPIFood();
}
requestAPIFood = _.debounce(() => {
this.setState({ loading: true });
const apiURL =
"https://api.edamam.com/api/food-database/v2/nutrients?app_id=${########}&app_key=${#######}";
fetch(apiURL)
.then((res) => res.json())
.then((resJson) => {
this.setState({
loading: false,
data: resJson,
fullData: resJson,
});
})
.catch((error) => {
this.setState({ error, loading: false });
});
}, 250);
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View
style={{ paddingVertical: 20, borderTopWidth: 1, borderColor: "red" }}
>
<ActivityIndicator animating size="large" />
</View>
);
};
_renderItem = ({ item, index }) => {
return (
<TouchableOpacity style={{ height: hp("5%") }}>
<Text style={{ left: wp("1%") }}>{item.food}</Text>
</TouchableOpacity>
);
};
handleSearch = (text) => {
const data = _.filter(this.state.fullData);
this.setState({ data, query: text });
};
render() {
return (
<SearchBar
placeholder="Search Food..."
onChangeText={this.handleSearch}
value={data}
/>
<List >
<FlatList
data={this.state.data}
renderItem={this._renderItem}
keyExtractor={(item, index) => index.toString()}
ListFooterComponent={this.renderFooter}
/>
</List>
Good evening, I'm working on a SearchBar component to search food from the API database of Edamam (this is the link to the documentation: https://developer.edamam.com/food-database-api-docs) and display the result on a FlatList as you can see above, but when I start typing nothing will appear and I really can't seem to find the error.

i want to re create Flatlist every time in react native

Please check shared video form understanding my issue
https://drive.google.com/file/d/1GKU07Mv7IjiLnrfps5gWpfMPsMphvRDv/view
I need to Flatlist screen every time empty because this below code every time Flatlist API called and then after change Flatlist data.
App Flow
first screen: shows category
second screen: shows selected category quotes
import { StyleSheet,Button,View, Text,FlatList,Dimensions,TouchableHighlight,Clipboard,ToastAndroid,Share,YellowBox } from 'react-native';
import { createAppContainer,NavigationEvents } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import { createDrawerNavigator } from 'react-navigation-drawer';
import { createSwitchNavigator } from 'react-navigation-switch-transitioner'
import Icon from 'react-native-vector-icons/Ionicons';
import Style from '../constants/Style';
import Spinner from 'react-native-loading-spinner-overlay';
export default class QuoteActivity extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('Title', 'Default Title'),
headerStyle: {
backgroundColor: navigation.getParam('BackgroundColor', '#5F4B8BFF'),
},
headerTintColor: navigation.getParam('HeaderTintColor', '#fff'),
headerLeft: (
<Icon
style={{ paddingLeft: 15,paddingTop: 5,color:'#FFFFFF' }}
onPress={() => navigation.goBack(null)}
name="ios-arrow-back"
size={40}
/>
)
};
};
constructor(props) {
super(props);
YellowBox.ignoreWarnings([
'Warning: componentWillMount is deprecated',
'Warning: componentWillReceiveProps is deprecated',
]);
}
state = {
spinner: false,isLoading: false,
dataSource:[]
}
// ON FOCUS CALL API
componentDidMount() {
this._doApiCall();
}
// API CALL
_doApiCall = () => {
this.setState({
spinner: true,isLoading:true
});
const { navigation } = this.props;
let CategoryId = navigation.getParam('CategoryId');
fetch('API_URL', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
}
}).then((response) => response.json())
.then((responseJson) => {
this.setState({
// SAMPLE JSON
// {
// "data": [
// {
// "Id": "462",
// "CategoryId": "5",
// "Title": "Being 'Single' is My Attitude!"
// },
// {
// "Id": "464",
// "CategoryId": "5",
// "Title": "I never dreamed about success. I worked for it."
// }
// ],
// "success": "1",
// "message": "2 Quotes found.",
// "service_time": "0.030284881591797 seconds"
// }
// SAMPLE JSON END
spinner:false,isLoading:false,
dataSource:responseJson.data
})
})
.catch((error) => {
console.error(error);
});
};
// Copy to clipboard
writeToClipboard = async (text) => {
await Clipboard.setString(text);
ToastAndroid.show('Quote copied!', ToastAndroid.SHORT);
};
// Share quotes
shareQuotes = async (text) => {
const result = await Share.share({
message:text.toString()+'\n\n Download app from play store',
});
};
_keyExtractor = (item) => item.id;
// RENDER DATA ITEMS
_renderItem = ({item}) => {
return (
<View style={Style.CategoryTitleList}>
<Text style={Style.CategoryTitle}>{item.Title}</Text>
<View style={[{ flexDirection:'row',justifyContent: 'center',alignItems:'center',textAlign:'center',alignSelf:"center"}]}>
<Icon name="ios-copy" onPress={() => this.writeToClipboard(item.Title)} title="Copy" size={25} color="#5F4B8BFF" style={[{margin:5,alignItems:'flex-end',paddingTop:3,paddingRight:20,paddingLeft:20 }]} />
<Icon name="ios-share" onPress={() => this.shareQuotes(item.Title)} size={25} color="#5F4B8BFF" style={[{margin:5,alignItems:'flex-end',paddingTop:3,paddingRight:20,paddingLeft:20 }]} />
</View>
</View>
)
}
render() {
// RENDER DATA ITEMS INSIDE RENDER FNS
renderItem = ({ item, index }) => {
return (
<View style={Style.CategoryTitleList}>
<Text style={Style.CategoryTitle}>{item.Title}</Text>
<View style={[{ flexDirection:'row',justifyContent: 'center',alignItems:'center',textAlign:'center',alignSelf:"center"}]}>
<Icon name="ios-copy" onPress={() => this.writeToClipboard(item.Title)} title="Copy" size={25} color="#5F4B8BFF" style={[{margin:5,alignItems:'flex-end',paddingTop:3,paddingRight:20,paddingLeft:20 }]} />
<Icon name="ios-share" onPress={() => this.shareQuotes(item.Title)} size={25} color="#5F4B8BFF" style={[{margin:5,alignItems:'flex-end',paddingTop:3,paddingRight:20,paddingLeft:20 }]} />
</View>
</View>
);
};
return (
<View style={Style.QuotesListView}>
<NavigationEvents
onDidFocus={this._doApiCall}
onWillFocus={() => this.setState({spinner: true})}
/>
<FlatList
data={this.state.dataSource}
renderItem={renderItem} // USED INSIDE RENDER FNS
refreshing={this.state.isLoading}
onRefresh={this._doApiCall}
maxToRenderPerBatch={10}
updateCellsBatchingPeriod={1000}
initialNumToRender={1}
removeClippedSubviews={false}
keyExtractor={this._keyExtractor}
/>
</View>
);
}
}```
Before doing the API Call you can clean the DataSource array that you have.
// API CALL
_doApiCall = () => {
this.setState({
spinner: true,isLoading:true,
dataSource: []
});
...
You can handle that in 2 different ways.
whenever you call _doApiCall function, change initial value of dataSource as an empty array.
_doApiCall = () => {
this.setState({
spinner: true,
isLoading: true,
dataSource: []
});
}
Using ternary operator, diaplay spinner when data loading & if not diaplay faltlist
{
this.state.isLoading ?
<Show your Spinner /> :
<FlatList
data={this.state.dataSource}
renderItem={renderItem}
refreshing={this.state.isLoading}
onRefresh={this._doApiCall}
maxToRenderPerBatch={10}
updateCellsBatchingPeriod={1000}
initialNumToRender={1}
removeClippedSubviews={false}
keyExtractor={this._keyExtractor}
/>
}
Feel free for doubt. hope this helps you.

how to show a component depending of picker value selected? [React native]

I'm trying to make a game with react native and I want to show a different options when i change the picker value.
basically when I select the first option on the picker a component has to appear and when I select the second one another component.
I tried this function but not working
pickerOptionText = () => {
if (this.state.PickerValueHolder==this.state.filter[0]) {
return (
<Text>{instructions[2]}</Text>
);
}else {
return (
<Text>{instructions[1]}</Text>
);
}
return null;
}
here is my code
export default class Facil extends Component {
constructor(props)
{
super(props);
this.state = {
isLoading: true,
PickerValueHolder : '',
filter: [
{
"option":"Palabras por categoria"
},
{
"option":"Palabras por caracteres"
}
],
dataSource:[]
}
}
componentDidMount() {
return fetch(API_URL)
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson
})
})
.catch((error) => {
console.error(error);
});
}
render() {
const resizeMode = 'stretch';
pickerOptionText = () => {
if (this.state.PickerValueHolder==this.state.filter[0]) {
return (
<Text>{instructions[2]}</Text>
);
}else {
return (
<Text>{instructions[1]}</Text>
);
}
return null;
}
return (
<View style={styles.container}>
<Image source={require('../../Images/HomeLayout.png')}
style={styles.imagen}
/>
<View style={styles.mView}>
<View style={styles.panel}>
<Text style={styles.titlePanel}>MODO FACIL</Text>
<Text style={styles.instructions}>{instructions[0]}</Text>
<View style={styles.picker}>
<Picker
selectedValue={this.state.PickerValueHolder}
style={ {height: '100%',width: '100%'}}
mode="dropdown"
onValueChange={(itemValue, itemIndex) => this.setState({PickerValueHolder: itemValue})} >
{ this.state.filter.map((item, key)=>(
<Picker.Item label={item.option} value={item.option} key={key} />)
)}
</Picker>
</View>
<View style={styles.gameOpt}>
<Text>[dynamic options]</Text>
{pickerOptionText}
</View>
</View>
</View>
<TouchableOpacity style={styles.button}><Text style={styles.btnText}>Play!</Text></TouchableOpacity>
</View>
);
}
}
You forgot '()'.
pickerOptionText is a function, not a React component.
<Text>[dynamic options]</Text>
{pickerOptionText}
to:
<Text>[dynamic options]</Text>
{pickerOptionText()}
You can try using Conditional Rendering of JSX, by this you can use ternary operator and a simple if condition. this is written as:
{this.state.PickerValueHolder==this.state.filter[0] ?
<Text>{instructions[2]}</Text>
:<Text>{instructions[1]}</Text>
}
and if you need simple if condition then,
{ condition == true && <Text>your text here</Text>
}

Categories

Resources