How to change icons onPress in React Native - reactjs

Im new to React Native so excuse the question if this is simple.
Im trying to toggle icons in a ListView. I'm logging out the correct response but Im unable to see the screen refresh onPress with that icon using "this.state". How should I go about this? Your help is much appreciated.
Here's a piece of code i'm working with.
getInitialState: function() {
return {liked:false};
},
pressedLike: function(){
this.setState({liked: !this.state.liked})
},
renderRow: function (data) {
return (
<View>
<TouchableHighlight
onPress={()=>{this.pressedLike}}>
<View>
{this.state.liked ? <Icon name="ios-heart" size={25} color="red" /> : <Icon name="ios-heart-outline" size={25} color="#555" />}
</View>
</TouchableHighlight>
</View>
);
},
render: function() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
refreshControl={
<RefreshControl refreshing={this.state.refreshing} onRefresh= {this.onRefresh}/>
}
/>
);
}

It's pretty simple, here is an example of how to change an Awesome icon on press... using the node_module react-native-vector-icon available on GitHub.
First in getInitialState, declare a variable with the icon you want and a check var to know which logo to display:
return {logo: "star-o", check: false}
Then on the concerned button / clickable zone , add this method:
onPress={() => this.stateChange()}
And declare a stateChange method and add this:
this.state.check === false ? this.setState({logo:'star', check:true}) : this.setState({logo:'star-o', check:false})
This looks for the check var and changes the logo depending on its value. It is ternary syntax.

There's really a lot that needs to happen here. You're going to probably need some sort of data structure that has a liked boolean in it, something like this (just an example):
data = [{name: 'Dog', liked: false}, {name: 'Turtle', liked: false}, {name: 'Cat', liked: false}]
Then in your likeItem method, you will need to get the index of the item you are looping over and update the liked boolean, and reset the state of the dataSource:
likeItem (index) {
const { data } = this.state
data[index].liked = !data[index].liked
this.setState({ dataSource: ds.cloneWithRows(data), data })
}
And you can show the icon based on the liked value:
{rowData.liked && <LikedIcon />}
{!rowData.liked && <NotLikedIcon />}
I wipped up a quick example of the functionality you may need here.
https://rnplay.org/apps/H2hsSg

Related

Passing a button select choice back to previous screen

So after some research, I have learned how to make a button that will take the user to another screen, and provide them a text input where they can enter some words, then on pushing the done button take them back to the previous screen where what they typed will be displayed. But for my particular needs, I am trying to figure out how to instead of a text input have a selection of buttons, such as "large, medium, small" and have that button select the data that would be displayed instead, and return them to the previous page where it is displayed.
initial screen
function HomeScreen( route ) {
navigation = useNavigation();
React.useEffect(() => {
if (route.params?.post) {
}
}, [route.params?.post]);
return (
<View>
<Pressable
title="Create post"
onPress={() => navigation.navigate('CreatePost')}
>
<Text style={{ margin: 10 }}>Post: {route.params?.post}</Text>
</Pressable
</View>
);
}
button selection screen
function CreatePostScreen( route ) {
const navigation = useNavigation();
const [postText, setPostText] = React.useState('');
return (
<>
<Pressable
title="Done"
onPress={() => {
navigation.navigate({
name: 'Home',
params: { postText },
merge: true,
});
}}
>
<Text>
Large
</Text>
</Pressable>
</>
);
}
any insight is greatly appreciated.
You can pass the data in form of object
{post: postText,
buttonType: 'medium'}
For getting the data
React.useEffect(() => {
if (route.params?.post) {
var buttonType= route.params?.buttonType
}
}, [route.params?.post]);
You can store the button type in a variable or state
var buttonType = route.params?.buttonType
Or You can try with useState() hooks
const [buttonType, setButtonType]=useState("")
setButtonType(route.params?.buttonType)
The for using it just do the following
<Text>{buttonType}</Text>
Please follow the React-Documentation

REACT NATIVE - this.setState doesn't work inside onChangeText

I'm trying to create a conditional onPress here using a gender selection. If the gender is undefined, I can't go on. Quite simple. But I'm a newbie and I'm not finding the trouble here.
That's the gender prop in state...
constructor(props) {
super(props);
this.state = {
gender: ''
};
That's the const genderSelect with these 3 gender values...
render() {
const genderSelected = [
{ value: 'Feminino', label: 'Feminino' },
{ value: 'Masculino', label: 'Masculino' },
{ value: 'Outro', label: 'Outro' }
];
...
}
That's my Dropdown class where I call the genderSelect and try to use the setState (but it doesn't work, the 'console.log' keeps returning 'undefined'). And finally, that's my conditional onPress.
return (
<>
<Dropdown
label='Selecione...'
data={genderSelect}
baseColor={"white"}
textColor={"white"}
itemColor={"white"}
pickerStyle={{
backgroundColor: "black"
}}
onChangeText={(value) => {
this.setState({ gender : value })
console.log(this.gender)
}}
/>
<TouchableOpacity
style={styles.buttonContainer}
onPress= {()=>{
if (this.gender != undefined ) {
console.log(this.gender)
this.props.navigation.navigate("Abas")
}
else {
console.log(this.gender)
Alert.alert('Ops!','Favor preencher sua idade e gênero antes!');
}
}}
>
<Text style={styles.buttonText}>CONFIRMAR</Text>
</TouchableOpacity>
Btw, I suppose the problem ocurrs inside the onChangeText / setState section. No matter how I use 'if / else' afterwards, it keeps returning 'undefined'.
It’s probably a simple issue whose cause I didn’t get, I know. And I've searched a lot about it, but none of the answers actually helped me. Hope someone can help me.
Replace this.gender with this.state.gender
That's the error.. gender is a state variable so you have to access it like that.
In your return part change this
<TouchableOpacity
style={styles.buttonContainer}
onPress={() => {
if (this.state.gender != undefined) {
console.log(this.state.gender);
this.props.navigation.navigate('Abas');
} else {
console.log(this.state.gender);
Alert.alert('Ops!', 'Favor preencher sua idade e gênero antes!');
}
}}>
<Text style={styles.buttonText}>CONFIRMAR</Text>
</TouchableOpacity>

React Native scrollview infinitely rerendering

I'm new to react native and I'm creating a to do list app. the component I wrote keeps infinitely re-rendering when I initialize Todos state to something that isn't an empty array. This results to an error where react stops it. I have no idea what is causing the infinite loop as I haven't included any recursion or explicit loops. I added a few console.log()'s everywhere and found that deleteTodo and toggleTodo keep getting called automatically until the application crashes.
When Todos state is initialized to an empty array I get an error saying that getTodos.map is not a function.
The component is only expected to re-render whenever the state is updated to either modify , add or delete a task.
import React, { useState } from 'react'
import { Platform, StyleSheet, Text, View, TouchableHighlight } from 'react-native'
import { State, ScrollView } from 'react-native-gesture-handler'
/* All required imports are correctly added */
let id = 0
function TaskRow(props) {
return (
<View>
{/* empty button acting as checkbox */}
<TouchableHighlight>
<Text />
</TouchableHighlight>
{/* main text area, displays task and all details + tags*/}
<TouchableHighlight onPress={props.toggle(props.key)}>
<Text>{props.task}</Text>
</TouchableHighlight>
{/* delete button */}
<TouchableHighlight onPress={props.delete(props.key)}>
<Text>Delete</Text>
</TouchableHighlight>
</View>
)
}
export default function TodoList() {
const [
getTodos,
setTodos,
] = useState([
{ key: id, task: 'this is a task', checked: false },
])
const addTodo = (taskInput = 'sample') => {
id++
setTodos(getTodos.push({ key: id, task: 'task', checked: false }))
}
const deleteTodo = (deleteID) => {
setTodos(getTodos.filter((match) => match.key !== deleteID))
}
const toggleTodo = (toggleID) => {
setTodos(
getTodos.map((match) => {
if (match.key == toggleID) return { key: match.key, task: match.task, checked: !match.checked }
}),
)
}
return (
<View>
<TouchableHighlight onPress={addTodo}>
<Text>Add task</Text>
</TouchableHighlight>
<ScrollView>
{getTodos.map((task) => (
<TaskRow
key={task.key}
task={task.task}
delete={deleteTodo}
toggle={toggleTodo}
/>
))}
</ScrollView>
</View>
)
}
You have a problem in your TaskRow component, on each render you are actually calling the functions instead of declaring an handler for events. Please chenge these two lines in this way:
// ...
<TouchableHighlight onPress={() => props.toggle(props.key)}>
// ...
<TouchableHighlight onPress={() => props.delete(props.key)}>
Another problem is this:
setTodos(getTodos.push({ key: id, task: 'task', checked: false }))
the .push() does not return the array so you should do something like:
setTodos([...getTodos, { key: id, task: 'task', checked: false }])

React Native : How to open a specific URL with onPress function from an array of urls?

I have an array of urls like that:
[ "https://hey.com",
"https://yes.com",
"https://wow.com",
/..
]
I have the same icon but multiple times. I want each of them to redirect to its specific url when on pressed.
I tried this code but it's not working:
onPress=(arrayOfURL)=>{
for (i in arrayOfURL)
{
this.setState({ browserOpen: true });
WebBrowser.openBrowserAsync(JSON.stringify(arrayOfURL[i]))
.then(() => {
WebBrowser.dismissBrowser();
this.setState({ browserOpen: false });
});
}
}
The code for the icon:
<View >
<Icon
name='sc-telegram'
type='evilicon'
color='black'
onPress={this.onPress} />
</View>
A quick help ! Have not tested the code, but this is what i do.
const urls = ["https://hey.com", "https://yes.com", "https://wow.com"];
urls.map(value => {
return <View>
<Icon
name='sc-telegram'
type='evilicon'
color='black'
onPress={() => this.openSpecificUrl(value)} />
</View>
})
onSpecificUrl = (specificUrl) => {
//you will get specific url from an array. You can perform your opening logic here
}
So it seems you're doing a logic error. You don't need a for loop, just call onPress() method by each icon passing it a parameter that specifies the link you want to be opened:
<Icon
name='sc-telegram'
type='evilicon'
color='black'
onPress={() => this.onPress(arrayOfURL[0])} />
And then simply:
onPress = (url) => {
[...]
WebBrowser.openBrowserAsync(url).then(...)
[...]
}
If your problem is how to assign your link to icons dynamically...well that's just an other question. I hope I haven't misunderstood everything this time and that this can helps you solve your doubts.

ScrollView Breaking When Adding Adjacent Component in React/js

I am working with React Native Web and Reactjs and I have the following code on one of my pages.
What I'm trying to do is make the background image and footer scrollable, while keeping the header (HorizontalNavBar) fixed at the top,. The ScrollView works fine when I don't try to render the VerticalNavBar over it, but breaks when I try to do so. It doesn't even work if the VerticalNavBar is present but rendering null.
Any help would be greatly appreciated. Attaching a screenshot. Thx!
var Home = React.createClass({
getInitialState: function() {
return {
source: homeImageSmall,
windowWidth: window.innerWidth,
tutorialDirection: 'row',
verticalNavOpen: false};
},
closeVerticalNav: function() {
this.setState({verticalNavOpen: false})
},
openVerticalNav: function() {
this.setState({verticalNavOpen: true})
},
render() {
return (
<View>
<View style={{flex:0}}>
<HorizontalNavBar verticalNavOpen = {this.state.verticalNavOpen} openVerticalNav = {this.openVerticalNav}/>
<ScrollView style={{flex:0}}>
<View>
<Image
style={contentStyle.backGroundImage}
source={this.state.source}>
<View style = {[styles.doubleIphoneWrapper, {flexDirection: this.state.tutorialDirection}]}>
<Tutorial content={Baseball} name={"Baseball"}/>
<Tutorial content={Football} name={"Football"}/>
</View>
</Image>
<Footer/>
</View>
</ScrollView>
<VerticalNav verticalNavOpen = {this.state.verticalNavOpen} closeVerticalNav = {this.closeVerticalNav}/>
</View>
</View>
)
}
})
Turns out I had overflow: hidden in my HTML file. The above code works if I remove that and set the position of both the horizontal and vertical menus to 'fixed'. #facepalm

Resources