Replace item in array react native - react-native

I'm new to js and react-native.
I have buttons on my app to change the languages, one button "English" and one button "Français".
const langues = [
{
id:0,
title: 'Français',
selected: true
},
{
id:1,
title: 'English',
selected: false
}
];
function Settings() {
return(
<View>
{langues.map(({title,selected}) => (
<View>
<Pressable style={styles.LanguesButton} >
{selected && <AntDesign size={15} name={'checkcircle'} /> }
<Text style={ {paddingLeft:selected ? 15 : 30} }>{title}</Text>
</Pressable>
</View>
))}
</View>
)
}
I would like to set selected to true for English, and false for Français when I click on "English" and same for "Français" but I don't understand how to do that.
PS: I already see that there are similar topics here but like I said I'm new to this language and I didn't understand the explanation on those topics ^^'.

First you need to create a state object that tells react native to render whenever it is updated like so;
import { useState } from "react";
const [languages, setLanguages] = useState([
{
id: 0,
title: 'Français',
selected: true
},
{
id: 1,
title: 'English',
selected: false
}
]);
Then you render this list. Whenever you press any language, you modify the state by calling setLanguages function like so;
const onPressed = (title) => {
let temp = [...languages];
temp.forEach(lang => {
if (lang.title == title) {
lang.selected = true;
}
else {
lang.selected = false;
}
});
setLanguages(temp);
}
function Settings() {
return (
<View>
{languages.map(({ title, selected }) => (
<View>
<Pressable style={styles.LanguesButton} onPress={() => {
onPressed(title);
}}>
</Pressable>
</View>
))}
</View>
)
}
After every press you will set the state and the screen will know that there has been a change and rerender.

Through onPress and find, like:
<Pressable onPress={ () =>
langues.find(lang.title === title).selected = true}>
https://reactnative.dev/docs/pressable#onpress

Related

Change color of button in a quiz depending on answer in React Native

I have a quiz written in React Native. When the user presses the right answer, I want the button to become green before moving to the next question. If it's wrong, I want the right answer to become green and the pressed button to become red. I'm quite new to React and not sure how to change state of only a particular button. How it looks now, all buttons becomes red/green as I set the background color for all the buttons.
Quiz screen:
state = {
correctCount: 0,
totalCount: this.props.navigation.getParam("questions", []).length,
activeQuestionIndex: 0,
answered: false,
answerCorrect: false,
btnColor: {backgroundColor: '#FFDD7C'}
};
answer = correct => {
this.setState(
state => {
const nextState = { answered: true };
if (correct) {
nextState.correctCount = state.correctCount + 1;
nextState.answerCorrect = true;
nextState.btnColor = {backgroundColor: '#00ff00'};
} else {
nextState.answerCorrect = false;
nextState.btnColor = {backgroundColor: '#ff0000'};
}
return nextState;
},
() => {
setTimeout(() => this.nextQuestion(), 750);
}
);
};
nextQuestion = () => {
this.setState(state => {
const nextIndex = state.activeQuestionIndex + 1;
if (nextIndex >= state.totalCount) {
this.props.navigation.navigate('QuizStatsScreen', {
totalQuizCount: state.totalCount,
correctQuizCount: state.correctCount
});
} else {
return {
activeQuestionIndex: nextIndex,
answered: false,
btnColor: {backgroundColor: '#FFDD7C'}
}
}
});
};
render() {
const questions = this.props.navigation.getParam("questions", []);
const question = questions[this.state.activeQuestionIndex];
return (
<View>
<StatusBar barStyle="light-content" />
<SafeAreaView style={styles.safearea}>
<View>
<Text style={styles.text}>{question.question}</Text>
<ButtonContainer>
{question.answers.map(answer => (
<Button
key={answer.id}
text={answer.text}
onPress={() => this.answer(answer.correct)}
style={this.state.btnColor}
correct={this.state.answerCorrect}
/>
))}
</ButtonContainer>
</View>
</SafeAreaView>
</View>
);
}
}
Button screen:
export const Button = ({ correct, text, style, onPress = () => {} }) => {
return (
<TouchableOpacity onPress={onPress} style={[styles.button, {...style}]}>
<Text style={styles.text}>{text}</Text>
</TouchableOpacity>
);
};
You can use one more variable as selectedId and in your state.
When your click on any answer then check if answer is right or wrong set answerCorrect true if right or false and then store your right and store answer.id to selectedId state.
<Button
....
style={
answer.id === selectedId && answerCorrect ?
styleForCorrectAnswer :
answer.id === selectedId && !answerCorrect ?
styleForWrongAnswer :
styleForDefaultAnswer
}
/>
What we are doing here is first we check if our answer.id match with selected answer id and answer is right. If yes then we are giving styleForCorrectAnswer else we are checking here if answer.id and selectedId match and user's answer is wrong then we are applying styleForWrongAnswer else styleForDefaultAnswer
Do something Like that change the state where you want and it will work
{this.state.correct
?
<TouchableOpacity onPress={onPress} style={{backgroundColor:'green'}}>
<Text style={styles.text}>Correct</Text>
</TouchableOpacity>
:
<TouchableOpacity onPress={onPress} style={{backgroundColor:'red'}}>
<Text style={styles.text}>False</Text>
</TouchableOpacity>
}

react-native changes the properties of the elements in the array?

I have a FlatList and I want to implement a radio button.My idea is to change the selected property of an element in this.state.data to control it,but I am a newbie, I don't know how to change the property of an element in this.state.data.
Here is my code:
this.state = {
data: [
{
month:1,
price:18,
selected:true
},
{
month:3,
price:48,
selected:false
},
{
month:12,
price:128,
selected:false
},
],
};
<FlatList
data={this.state.data}
renderItem={({item, index, separators}) => (
<TouchableOpacity onPress={() => this.radio(index,item)}>
<View style={item.selected ? {borderWidth:3,borderColor:'#FFA371',borderRadius:15}:{}}>
<View style={styles.itemDefalut}>
<View style={{ flexDirection: "column", flex: 1 }}>
<Text>
Months
</Text>
<Text>{item.month} Months</Text>
</View>
<View>
<Text>${item.price}</Text>
</View>
</View>
</View>
</TouchableOpacity>
)}
/>
radio(index,item) {
for (var variable in this.state.data) {
variable.selected = false;
}
item.selected = true;
}
first pass only index from onpress
onPress={() => this.radio(index)
then in radio function do something like this
radio = index => {
let data = [ ...this.state.data ];
this.state.data.map((elem,key)=>{
if(elem.month==data[index].month){
data[key]={...data[key], selected: true};
}else{
data[key]={...data[key], selected: false};
}
})
this.setState({ data:data});
}
radio(item) {
let data = [...this.state.data];
let index = data.findIndex(el => el.month === item.month);
data[index] = {...data[index], selected: !item.selected};
this.setState({ data });
}
In TouchableOpacity on press it should be
<TouchableOpacity onPress = {this.radio.bind(this,item)}>

React-Native-Component not rendering when state is changed

I am making the show more and show less functionality inside a flat list but the state pressed is not working as expected .When I am setting the state value component is not being rendered when the state changes its value.
My constructor is set like below
this.state = {
accList: [],
expanded: false,
expandedText: "Show More"
}
In componentdidmount() I am updating the value of accList value like below
componentDidMount = () => {
this.setState({
accList:[{
"customer_name": "Shubhangi J Thakur",
"message":"Hello"
},
{
"customer_name": "Arthur S Campbell",
"message":"Hello_World"
},
{
"customer_name": "Susan R Brill",
"message":"hellow"
}]
});
}
I have defined the flatlist in render() like below
<FlatList
onScroll={this.handleScroll}
data={this.state.accList}
renderItem={this.renderItem}
keyExtractor={this._keyExtractor}
/>
renderItem = ({ item, index }) => (
<Card style={style.cardLayout} key={index}>
<CardItem header>
<Text>{item.customer_name}</Text>
</CardItem>
{this.seemorefunctionality(item)}
</Card>
);
seemorefunctionality = (item) => {
return <View>
{this.state.expanded ? this.expandedView(item) :null}
//To view Show More and Show Less Text
<TouchableOpacity onPress={this.expandedText}>
<Text> {this.state.expandedText}</Text>
</TouchableOpacity>
</View>
}
}
expandedText = () => {
console.log('Setting the expanded text value', this.state.expanded)
if (this.state.expanded) {
this.setState({
expandedText: "Show More"
});
}
else {
this.setState({
expandedText: "Show Less"
});
}
value=!this.state.expanded
this.setState({
expanded: value
});
}
expandedView = (item) => {
return <View>
{item.map((obj, index) => {
return (
<View key={index} >
<Text>{obj.message}</Text>
</View>
)
})}
</View>
When I am clicking on the this.state.expandedText value is getting changed when we see in the console but its not reflecting in the View also expandedView is not being rendered when this.state.expanded is set to true.
In View the value of this.state.expandedText is always showing Show More while I can see In console that the value is getting changed to Show more and Show Less on click
for re-rendering flatlist you have to add extraData={this.state} as mention on https://facebook.github.io/react-native/docs/flatlist

Multiple switches enable all at once when generated from array react-native

What would you do to just enable the one switch (toggle) the user wishes to enable?
Here is my state:
state = {
menuItems: [
{ title: 'Test1', switchValue: false },
{ title: 'Test2', switchValue: false }
]};
Here is my constructor:
constructor(props: any) {
super(props);
this.toggle = this.toggle.bind(this);
}
And here is function control toggle:
toggle(item: any) {
const menu = [...this.state.menuItems];
menu[item].switchValue = !menu[item].switchValue;
this.setState({ menu });
}
And here is the map look like that:
public render() {
return (
<View style={styles.container}>
{this.state.menuItems.map((item, index) => (
<TouchableOpacity onPress={this.showSettingHint} key={item.title}>
<View style={[styles.rowContainer, index === 0 ? styles.topRowContainer : null]}>
<Text style={styles.title}>{item.title}</Text>
<Switch
onValueChange={this.toggle}
value={item.switchValue}
/>
</View>
</TouchableOpacity>
))}
</View>
);}
But I got an error like this:
undefined is not an object (evaluating 'menu[item].switchValue')
It may be that the toggle function expects an index for the menu item as an argument.
toggle(item: any) {
const menu = [...this.state.menuItems];
menu[item].switchValue = !menu[item].switchValue;
this.setState({ menu });
}
And in your Switch you are not passing the index of the menu item then, I think it would work if you pass the index in the onValueChange like so:
<Switch
//Add index here
onValueChange={this.toggle(index)}
value={item.switchValue}
/>

React Native onPress active state change image source on Carousel

Trying to change image of a button on my carousel elements, currently it (below code) changes all the images when I click any of them. I'd like change that only current carousel's image. Any ideas? Thanks
class CarouselImages extends React.Component {
constructor(props) {
super(props);
this.state = {
myImagesArray: [
{
key: 1,
title: 'Category'
},
{
key: 2,
title: 'Category'
},
{
key: 3,
title: 'Category'
}
],
icon_active: false,
}
activateCarouselButton = a => {
const newState = Object.assign(
{},
{
icon_active: false,
},
{ [a]: true },
)
this.setState(newState);
}
}
render = () => {
const { icon_active } = this.state;
var myCarousel = this.state.myImagesArray.map(function (index) {
return (
<View key={index}>
<TouchableHighlight onPress={() => activateCarouselButton('icon_active')} >
<Image
source={icon_active ? require('../Image/active#2x.png') : require('../Image/disabled#2x.png')} />
</TouchableHighlight>
</View>
);
});
return (
<View>
<Carousel
style={{ backgroundColor: '#fff' }}>
{myCarousel}
</Carousel>
</View>
)
}
}
You need to hold key of the icon in the icon_active state, not a boolean. This gives you a hunch on how to do it:
render() {
const { icon_active } = this.state;
return (
this.state.myImagesArray.map((image) => {
return (
<View key={image.key}>
<TouchableHighlight onPress={() => activateCarouselButton(image.key)}>
<Image source={icon_active === image.key ? require('../Image/active#2x.png') : require('../Image/disabled#2x.png')} />
</TouchableHighlight>
</View>
)
})
)
}
<Image source={this.props.secureTextEntry ?
require('../../assets/images/signup/Showpassword.png') :
require('../../assets/images/signup/Hidepassword.png')} />