I have a ScrollView and referencing it using ref but when I'm calling scrollTo of it, I am getting undefined is not an object.
next = () => {
this.scrollView.scrollTo({x:0, y:0, animated: true});
}
render() {
return(
<View>
<ScrollView ref={component => { this.scrollView = component }}>
<View></View>
<View></View>
<View></View>
</ScrollView>
<TouchableOpacity onPress={() => this.next()}>
<Text>Next</Text>
</TouchableOpacity>
</View>
)
}
The remedies that I have tried but never worked includes
using .bind(this) when calling the function
.bind(this) in the constructor
using refs ref='scrollView' and this.refs.scrollView
using arrow functions
Am I missing something here?
Try this,
next = () => {
this.scrollView.scrollTo({x:0, y:0, animated: true});
}
render() {
return(
<View>
<ScrollView ref={component => { this.scrollView = component }}>
<View></View>
<View></View>
<View></View>
</ScrollView>
<TouchableOpacity onPress={this.next}>
<Text>Next</Text>
</TouchableOpacity>
</View>
)
}
we need only one side binding.
Related
I know with the following code below changing a useState within another component's onPress event wouldn't be possible but how would I do it? I want to make it so when the onPress function within Card.js is executed the popUpData from within App.js is changed.
App.js
const [popUpData, setPopUpData] = React.useState("Nothing")
return (
<Card>
<Text style={styles.pokemonName}>{item.name}</Text>
</Card>
<Text>{popUpData}</Text>
)
Card.js
const doSomething = () => {
setPopUpData("Something")
//other things...
}
return (
<TouchableOpacity activeOpacity={1} style={styles.card} onPress={doSomething()}>
<View style={styles.cardContent}>
{ props.children }
</View>
</TouchableOpacity>
)
App.js
const [popUpData, setPopUpData] = React.useState("Nothing")
return (
<Card onUpdate={(d)=>setPopUpData(d) }>
<Text style={styles.pokemonName}>{item.name}</Text>
</Card>
<Text>{popUpData}</Text>
)
Card.js
function Card(props){
const doSomething = () => {
props.onUpdate("Something")
}
return (
<TouchableOpacity activeOpacity={1} style={styles.card} onPress={doSomething()}>
<View style={styles.cardContent}>
{ props.children }
</View>
</TouchableOpacity>
)
}
Just pass reference to setState function down to child component.
(in the simplest scenario)
const Parent = () => {
const [popUpData, setPopUpData] = React.useState("Nothing")
return (
<Card setPopUpDataHandler={setPopUpData}>
<Text style={styles.pokemonName}>{item.name}</Text>
</Card>
<Text>{popUpData}</Text>
)
}
const Card = ({setPopUpDataHandler, children}) => {
const doSomething = () => {
setPopUpDataHandler("Something")
//other things...
}
return (
<TouchableOpacity activeOpacity={1} style={styles.card} onPress={doSomething()}>
<View style={styles.cardContent}>
{ children }
</View>
</TouchableOpacity>
)
}
Have parent tag as <TouchableWithoutFeedback> and child as <Image>, trying to change the image source from the parent onPress function, but getting error. how can I archive this using refs? or any other way to resolve it?
React-native version : 0.56
Error :
Cannot read property 'favIcon' of undefined
Sample Code :
const fav = require('../../images/favorite.png');
const nonfav = require('../../images/not_favorite.png');
updateFavorite = (id) => {
this.props.refs.favIcon.source(fav);
}
render(){
return (
<View style={styles.container}>
<TouchableWithoutFeedback onPress={ this.updateFavorite.bind(this, 1) }>
<View style={ styles.imageView }>
<Image refs="favIcon" source={ nonfav } />
</View>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback onPress={ this.updateFavorite.bind(this, 2) }>
<View style={ styles.imageView }>
<Image refs="favIcon" source={ nonfav } />
</View>
</TouchableWithoutFeedback>
</View>
)
}
Note : change only the child image of onPressed, not all images.
try it using nativeProps, like
import resolveAssetSource from 'resolveAssetSource';
this.refs['favIcon'].setNativeProps({
src: [resolveAssetSource(fav)]
});
refer this for more.
It might not work with react-native 0.50+ versions but according to this comment it should work with 0.57.1
Updating properties of elements in React is best done by calling setState method. Try the following
updateFavorite = (event) => {
event.target.setAttribute('src', fav)
}
render(){
return (
<View style={styles.container}>
<TouchableWithoutFeedback>
<View style={ styles.imageView }>
<img ref={ref => this.favIcon = ref} src={nonFav} onPress={ this.updateFavorite }/>
</View>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback>
<View style={ styles.imageView }>
<img ref={ref => this.favIcon = ref} src={nonFav} onPress={ this.updateFavorite } />
</View>
</TouchableWithoutFeedback>
</View>
)
}
Whenever I tried to build UI from scratch I'm getting this error adjacent jsx element must be wrapped in an enclosing tag. I don't know how to solve this. Because I tried different methods, I've tried to put the blocks within View component withflex:1 but non-use. Is there any proper solution for this. This is becoming a great challenge for me because I can't design any components of my own. What to do please help me. Following is my code.
screen.js
export default class FirstScreen extends Component {
constructor(props){
super(props);
this.state = {
showPopupDialog: false,
workType: "",
workers: []
}
}
componentWillMount(){
fetch('http://192.168.1.6:3000/api/worker', {
method:'GET',
headers:{
Accept: 'application/json'
}
})
.then(response => response.json())
.then(responseData =>
this.setState({
workers:responseData
})
)
}
onPressYes = (workType) => {
console.log(workType);
}
popupDialog = (id, workType) => {
this.setState ({
showPopupDialog: true,
workType: workType
});
//make sure you set showPopupDialog to false and workType to "" when you click yes or no button in PopupDialog component so that it will work the next time you click on card
}
render() {
const { workers, workType, showPopupDialog} = this.state;
return (
<View style={{flex:1}}>
<Header />
<ScrollView>
{workers.map((a, index)=> (
<View style={{flex:1}}>
<CardSection>
<TouchableOpacity onPress={() => this.popupDialog(a.id, a.work_type)}>
<View style={{ maringTop: 10, marginLeft:120}}>
<Image style={{ height: 100, width: 100 }} source={{ uri: a.work_type == 'Carpenter' ? images[0].image : images[1].image}}/>
<Text style={{marginLeft:20, fontSize:20}}>{a.work_type}</Text>
</View>
</TouchableOpacity>
</CardSection>
</View>
))}
{showPopupDialog && <PopupDialog
dialogStyle={{ backgroundColor: "#FFFFFF", height: 180, width:300, borderWidth:1,padding:10}}
overlayBackgroundColor="#fff" dismissOnTouchOutside={true}>
<View style={styles.dialogContentView}>
<Text style={{fontSize:18, margingTop:10,color:"#000000"}}>Are you sure you want to submit?</Text>
<View style={{flexDirection:'row'}}>
<View style={styles.button_1}>
<Button title="Yes" color="#FF6633" onPress={() => this.onPressYes(workType)}/>
</View>
<View style={styles.button_1}>
<Button title="No" color="#FF6633" onPress={() =>this._onPressNo() }/>
</View>
</View>
</View>
</PopupDialog>}
</ScrollView>
</View>
);
}
}
The issue I'm facing is I can't place the <PopupDialog> component adjacent to <CardSection> , in order to that I put the <PopupDialog> within <View> ,even though it doesn't solve my issue.Please help..Please
Give a try with below corrected code.
There are two things that needs be corrected
You are doing .map but you are not returning anything which I have
corrected in the code below
export default class FirstScreen extends Component {
constructor(props){
super(props);
this.state = {
workType: "",
workers: []
}
}
componentWillMount(){
fetch('http://192.168.1.6:3000/api/worker', {
method:'GET',
headers:{
Accept: 'application/json'
}
})
.then(response => response.json())
.then(responseData =>
this.setState({
workers:responseData
})
)
}
onPressYes = (workType) => {
console.log(workType);
}
popUpDialog = (id, workType) => {
this.setState ({
workType: workType
});
this.popupDialog.show();
//make sure you set workType to "" when you click yes or no button in PopupDialog component so that it will work the next time you click on card
}
render() {
const { workers, workType} = this.state;
return (
<View style={{flex:1}}>
<Header />
<ScrollView>
{workers.map((a, index)=> (
<View style={{flex:1}}>
<CardSection>
<TouchableOpacity onPress={() => this.popUpDialog(a.id, a.work_type)}>
<View style={{ maringTop: 10, marginLeft:120}}>
<Image style={{ height: 100, width: 100 }} source={{ uri: a.work_type == 'Carpenter' ? images[0].image : images[1].image}}/>
<Text style={{marginLeft:20, fontSize:20}}>{a.work_type}</Text>
</View>
</TouchableOpacity>
</CardSection>
</View>
))}
<PopupDialog ref={popupDialog => {
this.popupDialog = popupDialog;
}}
dialogStyle={{ backgroundColor: "#FFFFFF", height: 180, width:300, borderWidth:1,padding:10}}
overlayBackgroundColor="#fff" dismissOnTouchOutside={true}>
<View style={styles.dialogContentView}>
<Text style={{fontSize:18, margingTop:10,color:"#000000"}}>Are you sure you want to submit?</Text>
<View style={{flexDirection:'row'}}>
<View style={styles.button_1}>
<Button title="Yes" color="#FF6633" onPress={() => this.onPressYes(workType)}/>
</View>
<View style={styles.button_1}>
<Button title="No" color="#FF6633" onPress={() =>this._onPressNo() }/>
</View>
</View>
</View>
</PopupDialog>
</ScrollView>
</View>
);
}
}
If I understand your question correctly...
You can return multiple root elements in jsx by wrapping is in a <React.Fragment> element (you can use <> and </> in v16.2 and later). Fragments are new in React v16. Prior to that, you just have to wrap them in some element (a div or span, usually).
The problem is that you have this structure:
<a>
{this.state.workers.map((a, index)=>
<b/>
<c/>
)}
</a>
Since <b/><c/> is parsed separately and there's no enclosing element, you're getting the error. But an enclosing element isn't necessary for the final structure, which does have an enclosing element. The solution is to simply return an array of JSX elements, like this:
<a>
{this.state.workers.map((a, index)=>
[<b/>,
<c/>]
)}
</a>
I am trying to open an item from my list but my item code is in another js. When I try to use onPress method there is no action. Also I am using Swipeout.
Here is my JobList.js where I am rendering the list of my items.
class JobList extends Component {
onJobDetails = (job) => {
this.props.navigate('JobDetails', job);
}
render() {
const { navigation } = this.props;
var renderJobs = () => {
return this.props.jobs.map((job) => {
return (
<JobItem
key={job._id}
title={job.title}
shortDescription={job.shortDescription}
logo={job.avatar}
company={job.company}
id={job._id}
dispatch={this.props.dispatch}
onPress={() => this.onJobDetails(job)}
/>
)
})
}
return (
<View style={styles.container}>
<ScrollView>
{renderJobs()}
</ScrollView>
</View>
);
}
};
And here is my JobItem.js
class JobItem extends Component {
render() {
return (
<Swipeout {...swipeSettings}>
<View style={styles.jobContainer}>
<View>
<Text style={styles.postTitle}>{this.props.title}</Text>
<Text style={styles.postShortDescription}>{this.props.shortDescription}</Text>
</View>
<View>
<Image
style={styles.postLogo}
source={{uri: '' + this.props.logo + ''}}/>
</View>
</View>
</Swipeout>
)
}
};
Any idea how shall I fix this?
You need to pass onPress prop to the child component in order for it to work.
<Swipeout {...swipeSettings}>
<TouchableWithoutFeedback onPress={this.props.onPress}>
//... other children here
</TouchableWithoutFeedback>
</Swipeout>
when I put onPress in a map loop, it doesn't work. how to fix it?
var PageOne = React.createClass({
_handlePress() {
this.props.navigator.push({id: 2,});
},
render () {
return (
<View>
<TouchableOpacity onPress={this._handlePress}> //work here
<Text> One </Text>
</TouchableOpacity>
<View style={styles.albums}>
{
list.map(function(item, index){
return (
<TouchableOpacity key={index} onPress={this._handlePress}> //doesn't work hehre
<Text>{item}</Text>
</TouchableOpacity>
)
})
}
</View>
</View>
);
}
});
this is referring to the wrong context, you need the scope to be lexically bound, which is what the fat arrow function will do for you.
Try calling your function like this:
onPress={ () => this._handlePress() }
Also, you need to bind the map function to the correct context like this:
<View style={styles.albums}>
{
list.map(function(item, index){
return (
<TouchableOpacity key={index} onPress={() => this._handlePress()}>
<Text>{item}</Text>
</TouchableOpacity>
)
}.bind(this))
}
</View>
Or like this:
<View style={styles.albums}>
{
list.map((item, index) => {
return (
<TouchableOpacity key={index} onPress={() => this._handlePress()}>
<Text>{item}</Text>
</TouchableOpacity>
)
})
}
</View>
I set up a working project here.
https://rnplay.org/apps/_PmG6Q