React-Native -> Couldn't change style using state - react-native

I've got a problem with my app. I'm trying to change style in my child component using states but unfortunately i dont get any results. I tried evrythig i know, but i dont know what is going on and why styles aren't changing at all
Here is parent :
constructor(props) {
super(props);
this.state = {
number: 1,
cords: [
],
choosenCords: [
],
style: {flex:1,flexDirection:'row',backgroundColor:'red'}
};
}
<View style={{ marginTop: 3 }}>
<ListItem style={this.state.style} test={this.state.test} title={item.timestamp} context={item.longtitude + " " + item.latitude} click={this.getData.bind(this, item.longtitude, item.latitude, item.timestamp)} />
</View>
getData = async(x, y, z) => {
let tempTab = []
tempTab.push(x)
tempTab.push(y)
tempTab.push(z)
const changeTest = this.state.test * (-1)
await this.setState({
choosenCords: [...this.state.choosenCords, tempTab],
style: {flex:1,flexDirection:'row',backgroundColor:'blue'}
})
}
}
This fragment of code represent changing style onPress. "choosenCords" are changing, but "style" don't.
Here is child:
class ListItem extends Component {
constructor(props) {
super(props);
this.state = {
test:this.props.test
};
}
render() {
return (
<View style={this.props.style}>
<Image
source={require('../Images/gps.png')}
style={{ borderWidth: 3, borderColor: '#7887AB', borderRadius: 50, marginLeft: 15, marginTop: 10 }}
/>
<View style={{ flex: 1, flexDirection: "column", marginBottom: 15, marginLeft: 10 }}>
<Text style={{ marginLeft: 10, fontSize: 16 }}>
{
"Timestamp: " + this.props.title
}
</Text>
<Text style={{ marginLeft: 15, fontSize: 15 }}>
{
"Cords:" + this.props.context
}
</Text>
</View>
<TouchableHighlight
underlayColor={'transparent'}
onPress={
this.props.click
}>
<Image
source={
require('../Images/check.png')
}
style={{ marginRight: 20 }}
/>
</TouchableHighlight>
</View>
);
}
Could someone help me with that?

You have to do like this:
const customStyle= this.state.test ? styles.custom_1: styles.custom_2
return <View
style={[ styles.anyStyle, customStyle]}
/>;
Define your custom style variable, set it based on state, then use it as an array for your element.

The child component does not automatically update when the state of the parent component changes. You'll need to update the state of the child component manually when the parent sends new props.
//in child component
componentDidUpdate(previousProps, previousState){
if(previousProps.style !== this.props.style){
//update child state here
this.setState({style: this.props.style})
}
}
Now instead of using "style={this.props.style}" in the child, use "style={this.state.style}"

It is happening because when you update your state, child component will not update automatically. you will get new updated value in componentWillReceiveProps() method.
your ListItem class will be like below:
class ListItem extends Component {
constructor(props) {
super(props);
this.state = {
test:this.props.test,
style:'' // take style into your state
};
}
componentWillMount(){
this.setState({style: this.props.style}) //set style
}
componentWillReceiveProps(newProps){
//called when you update style
if(newProps.style !== this.props.style){
this.setState({style: newProps.style})
}
}
render() {
return (
<View style={this.state.style}> //set style for views from state
// add your views here
</View>
);
}
}

Related

How to update the attribute of an item of a FlatList?

I have programmed an Android app which is consists of a TextInput, a Button and a FlatList. With each name That is written in the TextInput, there will be an item in the flat list. The Item title will be the TextInput content and there will be two buttons and a text right beside the list item. A button is for increasing the number that Text displays by 1 and the other one is for decreasing. here is my code:
import React, {Component} from 'react';
import {
View,
Text,
TextInput,
FlatList,
TouchableOpacity,
} from 'react-native';
import { ListItem, SearchBar} from 'react-native-elements';
class App extends Component {
constructor(props) {
super(props);
this.state = {
task: "",
task_array: [],
};
}
ChangeText = (some_task) => {
this.setState({task: some_task});
};
pushAdd = () => {
let contact = {
name: this.state.task,
counter: 0,
};
this.setState({task_array: [...this.state.task_array, contact]});
};
renderListItem = ({item}) => {
return(
<View style={{flexDirection: 'row'}}>
<ListItem title={item.name} style={{width:'75%', marginLeft:20}}></ListItem>
<View style={{flexDirection:'row'}}>
<TouchableOpacity style={{ backgroundColor: 'blueviolet', height: 20, width: 20, borderRadius: 50}} onPress={()=> item={name:item.name, counter:item.counter + 1}}><Text>+</Text></TouchableOpacity>
<Text>{item.counter}</Text>
//main problem <TouchableOpacity style={{ backgroundColor: 'blueviolet', height: 20, width: 20, borderRadius: 50 }} onPress={() => item = { name: item.name, counter: item.counter - 1 }}><Text>-</Text></TouchableOpacity>
</View>
</View>
);
};
render() {
return(
<View style={{ backgroundColor: 'mediumturquoise', width:'100%', height:'100%'}}>
<FlatList
data = {this.state.task_array}
renderItem = {this.renderListItem}
keyExtractor = {(item) => item.name}>
</FlatList>
<View style = {{flexDirection : 'row', alignContent:'center', alignItems:'center'}}>
<TextInput onChangeText={this.ChangeText} style={{ backgroundColor: 'burlywood', height:50, width:'75%', borderRadius:30, marginBottom:20, marginLeft:20, marginRight:20}}></TextInput>
<TouchableOpacity style={{ backgroundColor: 'chocolate', height:40, width:50, borderRadius:10, marginBottom:20}} onPress={this.pushAdd}></TouchableOpacity>
</View>
</View>
);
}
};
export default App;
I have pointed the problematic line with the comment 'main problem'. the increase and decrease button don't do their job and when I press them in the app, the number in the text remains unchanged. What change should I perform on the onPress method of my increase and decrease button to get them to work?
in React, you you can't manipulate data directly (like you are doing in your +/- buttons onPress methods). This will have no effect, instead, you need to change state appropriately by using setState
the fastest fix to this would be changing
// this
renderListItem = ({item}) => {
// to this
renderListItem = ({item, index}) => {
to know the index of rendered item. Then, change the onPress method of your increment/decrement buttons inside these item to utilize setState instead
// from this
onPress={()=> item={name:item.name, counter:item.counter + 1}}
// to this
onPress={() =>
this.setState({
task_array: this.state.task_array
.map((item, itemIndex) =>
itemIndex !== index
? item
: {
...item,
counter: item.counter + 1
})
})}
What happens here is we create a new task_array from the old one using .map() method of array, leaving every element untouched except the one element that was clicked - which we define by comparing indexes. In this case we increment it's counter and assign new value to task_array by using this.setState
Max’s answer is one way to realize, but the performance is not good, every time the child update, the all view is rendered again.
Here are my solution:
firstly, in the parent component register an event, which to receive the child update notice.
class App extends Component {
constructor(props) {
super(props);
this.state = {
task: "",
task_array: [],
};
}
// register the event,
componentDidMount() {
DeviceEventEmitter.addListener('itemUpdate', this.updateData)
}
componentWillUnmount () {
DeviceEventEmitter.removeListener('ModalVisible', this.updateData)
}
updateData = (params) => {
let copyTaskArray = {...this.state.task_array}
copyTaskArray[params.index].counter = params.counter
this.state.task_array = copyTaskArray
}
then we should move the FlatList Item into a single Component, and let it update the value
import React,{Component} from 'react';
import { View, TouchableOpacity,DeviceEventEmitter} from 'react-native';
export default class Item extends Component{
constructor(props) {
super(props);
this.state = {
counter:this.props.item.counter
};
}
plus = () => {
let oldCounter = this.state.counter;
let newCounter = oldCounter +1;
this.setState({
counter: newCounter
})
// notify the parent
DeviceEventEmitter.emit("itemUpdate",{index:this.props.index,counter:this.state.counter})
}
reduce = () => {
// the same with plus, only oldCounter -1
}
render() {
return(
<View key={this.props.index} style={{flexDirection: 'row'}}>
<ListItem title={this.props.item.name} style={{width:'75%', marginLeft:20}}></ListItem>
<View style={{flexDirection:'row'}}>
<TouchableOpacity style={{ backgroundColor: 'blueviolet', height: 20, width: 20, borderRadius: 50}} onPress={this.plus}>
<Text>+</Text>
</TouchableOpacity>
<Text>{his.props.item.counter}</Text>
<TouchableOpacity style={{ backgroundColor: 'blueviolet', height: 20, width: 20, borderRadius: 50 }} onPress={this.reduce}>
<Text>-</Text>
</TouchableOpacity>
</View>
</View>
)
}
}
In this situation, when the item scrolls over the screen and recreate, the value still exists.
In the end, we should change the parent item renderListItem method.
renderListItem = ({item, index}) => {
return(
<Item index={index} item={item} ></Item>
);
}
I hope this can help you.

Change active image react native

I wanna change the active image when it's pressed. So for example I have two zodiacs signs, Capricorn and taurus, and when the user click on Capricorn the image is rendered in color and if the user click on the taurus sign then the Capricorn sign will be in black and white and the taurus sign will be rendered in color. Actually I've only managed to change from black and white to color using states but it will always render the color image, I can't switch it on and off . Here is my code:
class Horoscope extends React.Component {
constructor(props) {
super(props)
this.state = {
belier:false,
balance:false,
cancer:false,
capricorne:false,
gemeaux:false,
lion:false,
poissons:false,
sagittaire:false,
scorpion:false,
taureau:false,
verseau:false,
vierge:false,
}
}
render() {
return (
<View style={styles.main_container}>
<View style = {{height: 150, backgroundColor: '#F5F5F5'}}>
<View style={{flexDirection:'row', justifyContent: 'space-around', marginVertical: 8 }}>
<TouchableOpacity onPress={() => {this.setState({belier: !this.state.belier})}}>
<Image style = {styles.image} source={ this.state.belier === true ? require("../Images/couleurs/icons8-belier-100.png")
: require("../Images/gris/beliergris.png")}/>
</TouchableOpacity>
<TouchableOpacity onPress={()=> {this.setState({taureau: !this.state.taureau})}}>
<Image style = {styles.image} source={this.state.taureau === true ? require("../Images/couleurs/icons8-taureau-96.png")
: require("../Images/gris/taureaugris.png")}/>
</TouchableOpacity>
</View>
</View>
</View>
)}
EDIT: I have also tried with a state clicked but still not know how to change his value to false when the user click on an other image..
You could have an Image mapper,
const Images = {
taureau: {
active: require("../Images/couleurs/icons8-taureau-96.png"),
inactive: require("../Images/gris/taureaugris.png")
},
belier: {
active: require("../Images/couleurs/icons8-belier-100.png"),
inactive: require("../Images/gris/taureaugris.png")
}
};
class Horoscope extends React.Component {
constructor(props) {
super(props)
this.state = {
belier:false,
balance:false,
cancer:false,
capricorne:false,
gemeaux:false,
lion:false,
poissons:false,
sagittaire:false,
scorpion:false,
taureau:false,
verseau:false,
vierge:false,
}
}
onPress = var => {
this.setState(state => ({
[var]: !this.state[var]
}));
}
getImage = var => {
const isActive = this.state[var];
const { active, inactive } = Images[var];
if(isActive) {
return active;
}
return inactive;
}
render() {
<View style={styles.main_container}>
<View style = {{height: 150, backgroundColor: '#F5F5F5'}}>
<View style={{flexDirection:'row', justifyContent: 'space-around', marginVertical: 8 }}>
<TouchableOpacity onPress={() => { this.onPress('belier') }}>
<Image source={() => { this.getImage('belier') }}/>
</TouchableOpacity>
</View>
</View>
</View>
}
}
So I found a way to have what I wanted using map() but I have a problem with the layout now. I have 12 images to render but I can only show 6. And I want to have them 6 on top and 6 just below. Here is the code if someone need it :
And if someone knows why I can't display my 12 images I would appreciate. (will edit if I found it). Thanks
class Horoscope extends React.Component {
constructor(props) {
super(props)
this.state = {
selectedIndex:0,
selectedIndex2:0,
belier:false,
balance:false,
cancer:false,
capricorne:false,
gemeaux:false,
lion:false,
poissons:false,
sagittaire:false,
scorpion:false,
taureau:false,
verseau:false,
vierge:false,
tabList:[
{label:'1', urlActive:require('../Images/couleurs/icons8-belier-100.png'), urlInactive:require('../Images/gris/beliergris.png')},
{label:'2', urlActive:require('../Images/couleurs/icons8-taureau-96.png'), urlInactive:require('../Images/gris/taureaugris.png')},
{label:'3', urlActive:require('../Images/couleurs/icons8-gemeaux-96.png'), urlInactive:require('../Images/gris/gemeauxgris.png')},
{label:'4', urlActive:require('../Images/couleurs/icons8-cancer-96.png'), urlInactive:require('../Images/gris/cancergris.png')},
{label:'5', urlActive:require('../Images/couleurs/icons8-lion-96.png'), urlInactive:require('../Images/gris/liongris.png')},
{label:'6', urlActive:require('../Images/couleurs/icons8-vierge-96.png'), urlInactive:require('../Images/gris/viergegris.png')},
{label:'7', urlActive2:require('../Images/couleurs/icons8-balance-96.png'), urlInactive2:require('../Images/gris/balancegris.png')},
{label:'8', urlActive2:require('../Images/couleurs/icons8-scorpion-96.png'), urlInactive2:require('../Images/gris/scorpiongris.png')},
{label:'9', urlActive2:require('../Images/couleurs/icons8-sagittaire-96.png'), urlInactive2:require('../Images/gris/sagittairegris.png')},
{label:'10', urlActive2:require('../Images/couleurs/icons8-verseau-96.png'), urlInactive2:require('../Images/gris/verseaugris.png')},
{label:'11', urlActive2:require('../Images/couleurs/icons8-capricorne-96.png'), urlInactive2:require('../Images/gris/capricornegris.png')},
{label:'12', urlActive2:require('../Images/couleurs/icons8-poissons-96.png'), urlInactive2:require('../Images/gris/poissonsgris.png')}
]
}
}
render() {
{console.log(this.state.selectedIndex)}
return (
<View style={styles.main_container}>
<View style = {{height: 150, backgroundColor: '#F5F5F5'}}>
<View style={{flexDirection:'row', justifyContent: 'space-between', flexWrap: 'wrap'}}>
{
//loop throught the state
this.state.tabList.map((item,index)=>{
return(
<View>
<TouchableOpacity onPress={()=>{this.setState({selectedIndex:index})}}>
<Image
style = {styles.image}
source={this.state.selectedIndex==index ? item.urlActive:item.urlInactive}/>
</TouchableOpacity>
</View>
)
})
}
</View>
</View>
</View>
)}
}
EDIT: Just using flexWrap: 'wrap'resolve it.

How to access one control property in another control in ReactNative

I want to access this.state.sampleString from HelloWorldApp component
class to CustomWebView component class in react native, but in alert
this.props.sampleString showing 'undefined'.
Here is my code:
class CustomWebView extends Component{
constructor(props){
super(props);
this.state = { text: 'http://www.google.com' };
}
render() {
alert(this.props.sampleString);
return (
<WebView
source={{uri:this.state.text}}
style={{marginTop: 50}}
/>
);
}
}
export default class HelloWorldApp extends Component {
constructor(props) {
super(props);
this.state = { sampleString: 'http://www.google.com' };
this.getValue = this.getValue.bind(this);
}
getValue(){
//console.log(this.state.sampleString);
return this.state.sampleString
}
handleClick = () => {
alert(this.state.sampleString);
}
render(){
const {isFocused} = this.state;
const{onFocus,onBlur} = this.props;
return (
<View style={{
flexDirection: 'column',
height: '100%',
paddingTop: 36
}}>
<View style={{
flexDirection: 'row',
height : '5%',
width : '100%',
justifyContent: 'flex-start',
paddingBottom:3,
paddingTop:1,
marginTop : 20
}}>
<TextInput
selectionColor = {BLUE}
ref = "urltext"
underlineColorAndroid={isFocused?BLUE:LIGHT_GRAY}
onFocus = {this.handleFocus}
onBlur ={this.handleBlur}
style={styles.textInput}
onChangeText={(sampleString) => this.setState({sampleString})}
value={this.state.sampleString}
/>
<Button title="Submit"
onPress = {this.handleClick.bind(this)}
color="#9933ff"
accessibilityLabel="TestButton"/>
</View>
<CustomWebView/>
</View>
);
}
}
})
I need to change url in class CustomWebView on the onPress event of Button in
HelloWorldApp class. And that's why i want to access this.props.sampleString in CustomWebView class.
use CustomWebView like this
<CustomWebView
sampleString={this.state.sampleString}
/>
Please do it as following:
<CustomWebView
sampleString={this.state.sampleString}
/>
on CustomWebView, you should use the props - sampleString, not state variable - text.
class CustomWebView extends Component{
constructor(props){
super(props);
this.state = { text: 'http://www.google.com' };
}
render() {
alert(this.props.sampleString);
return (
<WebView
source={{ uri: this.props.sampleString }}
style={{ marginTop: 50 }}
/>
);
}
}
First of all, you are using the wrong method to update the state at onChangeText as,
onChangeText={(sampleString) => this.setState({sampleString})}
when you use above method you can get an error like,
sampleState is not defined
because you have to define which state you want to update with the updated value in setState method. You have to update state as,
onChangeText={(inputText) => this.setState({sampleString: inputText})}
And then you can pass this sampleString in CustomWebView as prop,
<CustomWebView uri = {this.state.sampleString} />
Finally, you can access this prop in CustomWebView as,
<WebView
source={{ uri: this.props.uri }}
style={{ marginTop: 50 }}
/>
And all done :)
Note: - Because you are updating state at onChangeText, and simultaneously passing this state as prop in CustomWebView. CustomWebView can access this state without button click.
you have to take two state variable. fist for textInput and second is for rendering Webview, which you have to pass in CustomWebView component.
Your HelloWorldApp class should be like following:
export default class HelloWorldApp extends Component {
constructor(props) {
super(props);
this.state = {
textInputData: 'http://www.google.com'
sampleString: 'http://www.google.com'
};
}
handleClick(){
//set sampleString when click on button
this.setState({
sampleString: this.state.textInputData
})
}
render(){
const {isFocused} = this.state;
const{onFocus,onBlur} = this.props;
return (
<View style={{
flexDirection: 'column',
height: '100%',
paddingTop: 36
}}>
<View style={{
flexDirection: 'row',
height : '5%',
width : '100%',
justifyContent: 'flex-start',
paddingBottom:3,
paddingTop:1,
marginTop : 20
}}>
<TextInput
selectionColor = {BLUE}
ref = "urltext"
underlineColorAndroid={isFocused?BLUE:LIGHT_GRAY}
onFocus = {this.handleFocus}
onBlur ={this.handleBlur}
style={styles.textInput}
onChangeText={(inputText) => this.setState({textInputData: inputText})}
value={this.state.textInputData}
/>
<Button title="Submit"
onPress = {this.handleClick.bind(this)}
color="#9933ff"
accessibilityLabel="TestButton"/>
</View>
<CustomWebView
sampleString={this.state.sampleString} />
</View>
);
}
} })
and you will get updated sampleString in componentWillReceiveProps() of CustomWebView component
class CustomWebView extends Component{
constructor(props){
super(props);
this.state = {
text: 'http://www.google.com'
};
}
componentWillMount(){
this.setState({ text:this.props.sampleString })
}
componentWillReceiveProps(newProps){
//when will you update url in textinput and do submit. you will get updated
sampleString here.
this.setState({ text:newProps.sampleString })
}
render() {
return (
<WebView
source={{uri:this.state.text}}
style={{marginTop: 50}}
/>
);
}
}

Hide/Show dynamically created view - React Native

As I am working on react native platform, I have achieved many UI and dynamic challenges but here I have multiple view which I am creating dynamically as per the API response like
if data length is 3
for(i=0;i<data.length;i++)
{
this.setState({ responseData:
<View>
<Text>{data[i].title}</Text>
<Text>Click to view more +</Text>
<View style={{height: 0}}>
<Text>View {i}</Text>
<Text>{data[i].requesttext}</Text>
<Text>{data[i].responsetext}</Text>
</View>
</View>
})
}
render(
<View style={styles.maincontainer}>
{this.state.reponseData}
</View>
)
//Make sure that I have written the above code just for an understanding.
Output
--------------------------
Test Title 1
Click to view more -
View 0
this is request
this is response
--------------------------
Test Title 2
Click to view more +
--------------------------
Test Title 3
Click to view more +
--------------------------
Here if I have data length is 3, I am creating 3 views and rendering it. Now my requirement is how can I show or set height auto (as there is no any display none property available in react native) that particular view which I am clicking to view more
Is there anything like id or class for reference to that particular view to set style ?
I have tried refs Refs to Components but its giving me error something like parent view node etc., and actually I dont know how to use it.
Also setting state is also not possible as this is dynamic.
Please let me know if you are not getting my point, or suggest me anything to accomplish this. Thanks!
Try this code:
constructor:
var views = [];
for(i=0;i<data.length;i++)
{
views.push(
<View ref={ref=>this['view_'+i]}>
<Text>{data[i].title}</Text>
<Text>Click to view more +</Text>
<View style={{height: 0}}>
<Text>View {i}</Text>
<Text>{data[i].requesttext}</Text>
<Text>{data[i].responsetext}</Text>
</View>
</View>
}
}
this.state = {views};
render:
render(
<View style={styles.maincontainer}>
{{this.state.views}}
</View>
)
To hide any view:
onPress() {
const views = this.state.views;
// remove item that you want to hide here from views array
this.setState({views})
}
Try like below, split in to two components which will solve your issue.
Let say you have a data like below, Take the below as an example case for your issue
const sampleJson = [
{
id: 1,
name: "Green Tea",
description: "This is Green Tea",
imageurl: "https://www.mozismenu.com/wp-content/uploads/2017/04/Chicken-Keema-Samosa-0.jpg"
},
{
id: 2,
name: "Burger",
description: "This is Burger",
imageurl: "https://www.mozismenu.com/wp-content/uploads/2017/04/Chicken-Keema-Samosa-0.jpg"
},
{
id: 3,
name: "Pizza",
description: "This is Pizza",
imageurl: "https://www.mozismenu.com/wp-content/uploads/2017/04/Chicken-Keema-Samosa-0.jpg"
}
]
//HomePage Component
import Home from "../components/Home";
export default class HomePage extends Component{
render(){
return(
<ScrollView style={styles.container1}>
{ sampleJson.map((data, index) => {
return(
<View style={styles.container} key={data.id}>
<Text style={styles.welcome}>{data.name}</Text>
<Home display={false} data={data}/> //Here i'm sending the prop display as false initially for every view, and also sending the data as prop data.
</View>
)
})
}
</ScrollView>
)
}
}
const styles = StyleSheet.create({
container1: {
flex: 1,
backgroundColor: '#F5FCFF',
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
welcome2: {
fontSize: 16,
textAlign: 'center',
margin: 5,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
container3: {
backgroundColor: '#0098cd',
display: "none"
}
});
//Home Component
export default class Home extends Component{
constructor(props){
super(props);
this.state = {
show: this.props.display, //Each one will depend on its own state
data: this.props.data
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome} onPress={()=> this.setState({ show: !this.state.show})}>Click to view more +</Text> //It will set the flag is false if true and will set as true if false.
//If the show prop in state is false, it renders null
{ this.state.show === true
? ( <View style={styles.container3}>
<Text style={styles.welcome2}>View </Text>
<Text style={styles.welcome2}>{this.state.data.description}</Text>
</View>
)
: null
}
</View>
);
}
}

React Native - Changing States in an Array of another file

Hey Everyone :) This is my first post here, hope I am doing everything correctly!
I am currently working on a school project and using react-native for some weeks now.
My Problem:
I have the file data.js:
const cardOne_1 = require("../images/Vergleiche/Eisbär.jpg");
const cardTwo_1 = require("../images/Vergleiche/Android.jpg");
const cardThree_1 = require("../images/Vergleiche/Han_Solo_Alt.jpg");
const cardOne_2 = require("../images/Vergleiche/Gorilla.jpg");
const cardTwo_2 = require("../images/Vergleiche/Apple.jpg");
const cardThree_2 = require("../images/Vergleiche/Han_Solo_Jung.jpg");
export default[
{
image: cardOne_1,
image2: cardOne_2,
text: '53%',
text2: '47%',
title: 'Icebear vs Gorilla',
check: false,
},
{
image: cardTwo_1,
image2: cardTwo_2,
text: '19%',
text2: '81%',
title: 'Android vs IOS',
check: true,
},
{
image: cardThree_1,
image2: cardThree_2,
text: '70%',
text2: '30%',
title: 'Han Solo',
check: false,
},
];
My Homescreen contains two of these Deckswipers (For better clarity I will show here only the code for the first one), which are used to compare two images:
Homescreen - With two DeckSwiper
import data from '../Data.js';
export default class SwipeCards2 extends Component {
_onSwipeLeft() {
this._deckSwiper1._root.swipeLeft();
this._deckSwiper2._root.swipeRight();
}
_onSwipeRight() {
this._deckSwiper2._root.swipeLeft();
this._deckSwiper1._root.swipeRight();
}
render() {
return (
<Container style={{ backgroundColor: '#ffffff' }}>
<View>
<DeckSwiper
ref={mr => (this._deckSwiper1 = mr)}
dataSource={data}
onSwipeRight={() => this._deckSwiper2._root.swipeLeft()}
onSwipeLeft={() => this._deckSwiper2._root.swipeRight()}
looping={true}
renderEmpty={() => (
<View style={{ alignSelf: 'center' }}>
<Text>Das war´s!</Text>
</View>
)}
renderItem={item => (
<Card
style={{
elevation: 3,
height: 335,
justifyContent: 'center',
width: Dimensions.get('window').width + 1,
marginLeft: -1,
marginTop: 0,
}}>
<TouchableWithoutFeedback onPress={() => this._onSwipeRight()}>
<CardItem cardBody style={{ alignItems: 'center' }}>
<Image
style={{
resizeMode: 'cover',
flex: 1,
height: 335,
}}
source={item.image}
/>
</CardItem>
</TouchableWithoutFeedback>
</Card>
)}
/>
</View>
</Container>
);
}
}
I want to set the state "check" in data.js to true, everytime the user does swipe to the right.
A Third Screen renders a List component, which should show the previous made decisions of the user. This list is based on "check" of data.js.
Screen 3 - List of all the decisions
I tried for almost three days and can not find any good solution!
Do you have any suggestions how to achieve this?
Thanks :)
I'm not sure how things work with this DeckSwiper component but since you are importing a static data, if you need to change the data you need to clone it and then change it. Assigning data clone to a state variable and then giving it to the component will reflect the changes to the component.
To change a property on a specific object in your array you also need an unique identifier like an ID or similar.
Example
import data from '../Data.js';
export default class SwipeCards2 extends Component {
constructor(props) {
super(props);
// clone the static data to state
this.state = {
data: [...data]
}
}
changingCheckFunction(obejctsUniqueId) {
this.setState((prevState) => {
// find the object's id
const itemIndex = prevState.data.findIndex(x => x.id == obejctsUniqueId);
// copy the item and assign the new checked value
const newItem = Object.assign({}, prevState.data[itemIndex], { checked: !prevState.data[itemIndex]});
// copy the previous data array
const newData = [...prevState.data];
// set the newItem to newData
newData[itemIndex] = newItem;
// return the new data value to set state
return { data: newData };
});
}
_onSwipeLeft() {
this._deckSwiper1._root.swipeLeft();
this._deckSwiper2._root.swipeRight();
}
_onSwipeRight() {
this._deckSwiper2._root.swipeLeft();
this._deckSwiper1._root.swipeRight();
}
render() {
return (
<Container style={{ backgroundColor: '#ffffff' }}>
<View>
<DeckSwiper
ref={mr => (this._deckSwiper1 = mr)}
dataSource={this.state.data}
onSwipeRight={() => this._deckSwiper2._root.swipeLeft()}
onSwipeLeft={() => this._deckSwiper2._root.swipeRight()}
looping={true}
renderEmpty={() => (
<View style={{ alignSelf: 'center' }}>
<Text>Das war´s!</Text>
</View>
)}
renderItem={item => (
<Card
style={{
elevation: 3,
height: 335,
justifyContent: 'center',
width: Dimensions.get('window').width + 1,
marginLeft: -1,
marginTop: 0,
}}>
<TouchableWithoutFeedback onPress={() => this._onSwipeRight()}>
<CardItem cardBody style={{ alignItems: 'center' }}>
<Image
style={{
resizeMode: 'cover',
flex: 1,
height: 335,
}}
source={item.image}
/>
</CardItem>
</TouchableWithoutFeedback>
</Card>
)}
/>
</View>
</Container>
);
}
}