I have this structure, where I have a list of MyComponent:
class MyComponent extends Component
{
props: { navigation: Object, data: Object };
ShowScreenB(data: Object){
this.props.navigation.navigate('ScreenB', {data});
}
render()
{
return (
<Menu>
<MenuTrigger> <Text> Menu </Text> </MenuTrigger>
<MenuOptions>
<MenuOption onSelect={() => this.ShowScreenB.bind(this, this.props.data)} text='Show Screen B' />
</MenuOptions>
</Menu>
);
}
}
class MyScreen extends Component
{
render()
{
let renderRow = (row) => { return (<MyComponent data= {row} navigation= {this.props.navigation} /> );}
return (
<View >
<ListView dataSource={this.state.DataSource} renderRow={renderRow.bind(this)}/>
</View>
);
}
}
But ShowScreenB() does not go to the other screen.
I also tried to prepare the navigator in MyScreen class and then pass it as a function to MyComponent. But also does not work:
class MyComponent extends Component
{
props: { OnPress: Function, data: Object };
render()
{
return (
<Menu>
<MenuTrigger> <Text> Menu </Text> </MenuTrigger>
<MenuOptions>
<MenuOption onSelect={() => this.OnPress.bind(this)} text='Show Screen B' />
</MenuOptions>
</Menu>
);
}
}
class MyScreen extends Component
{
ShowScreenB(data: Object){
this.props.navigation.navigate('ScreenB', {data});
}
render()
{
let renderRow = (row) => { return (<MyComponent data= {row} OnPress= {this.ShowScreenB.bind(this, row)} /> );}
return (
<View >
<ListView dataSource={this.state.DataSource} renderRow={renderRow.bind(this)}/>
</View>
);
}
}
What could be the issue?
Edit: Menu is a PopUp Menu.
You never call ShowScreenB().
Right now you are just binding it:
onSelect={() => this.ShowScreenB.bind(this, this.props.data)}
bind doesn't call the function. All it does it bind it to the given context. You need to actually call ShowScreenB() so your navigation code executes. For example:
onSelect={() => { this.ShowScreenB.bind(this); this.ShowScreenB(this.props.data); }}
Edit to answer comment since it won't fit in a comment:
That's because removing ( ) => makes it so all you have is the { } syntax leftover. { } means to evaluate what is inside the brackets. Take a look at what is written in the link in my answer. The return value of bind is:
A copy of the given function with the specified this value and initial arguments.
So the expression { this.ShowScreenB.bind(this) } will evaluate the return value; hence calling the navigation function. What I posted above was simply one example of what you could do. You could just as well write it as onSelect={() => this.ShowScreenB.bind(this)()} and it would work as well. If you're having trouble with this, you should also brush up on how arrow functions work.
Related
I have a question about passing specific Objects from an array to another class in react native. If I press the button, all objects go to another class instead of the one I need, but I want the one which I pressed. Do I have to create a function for the selected object/ key or is it enough if I change something in the onPress={} method?
I need to change something here -> TouchableOpacity onPress={()=>this.props.navigation.navigate('detail', item,{})}> Item must be the document (firestore) with all the information I have, but how can I pass the object from the array only?
Here are also some pictures for a better understanding, thank you in advance
export default class foods extends Component {
constructor(props) {
super(props);
this.state = {
posts:[],
}
}
componentDidMount() {
StatusBar.setHidden(true)
this.subscriber = database.collection('users').onSnapshot(docs => {
let posts = []
docs.forEach(document => {
posts.push({
id: document.id,
...document.data(),
})
})
this.setState({posts})
console.log(posts)
})
}
render() {
return (
<ScrollView>
<View style={styles.container}>
{
this.state.posts.map((item) => {
return (
<View >
{
Object.keys(item.post).map((key) => {
return (
<View style={styles.card}>
<TouchableOpacity onPress={() => this.props.navigation.navigate('detail', item, {})}>
<Text>{item.firstName} {item.lastName}</Text>
<Image style={styles.cardImage} source={{ uri: item.post[key].image }} />
<Text>{item.post[key].essenname}</Text>
</TouchableOpacity>
</View>
)
})
}
</View>
)
})
}
</View>
</ScrollView>
);
}
}
export default class detail extends Component {
constructor(props) {
super(props);
this.state = {
post: [this.props.route.params]
}
};
componentDidMount() {
StatusBar.setHidden(true)
console.log('Array : ', this.state.post)
}
render() {
return (
<View style={styles.container}>
<ScrollView>
{this.state.post.map((item) => {
return (
Object.keys(item.post).map((key) => {
return (
<View style={styles.card}>
<Image style={styles.cardImage} source={{ uri: item.post[key].image }} />
<Text>{item.post[key].essenname}</Text>
</View>
)
})
)
})}
</ScrollView>
</View>
);
}
}
I want to pass either Post[0] or Post[1] but not both:
![](https://i.stack.imgur.com/3recX.png)
This is my output, which is the same output after navigating the item to the detail screen:
![](https://i.stack.imgur.com/WMqrd.png)
Detail screen on the right:
![](https://i.stack.imgur.com/gIX0V.png)
The document with the array 'post':
![](https://i.stack.imgur.com/dO1uQ.png)
There is no need to use Object.keys to loop trought your posts, just use item.post.
In your navigation params, just use a spred operator for the root key and pass the post selected: this.props.navigation.navigate('detail', {posts: {...this.state.posts, post: [p]}}).
In your detail component state your are missing to access the params, it should be:
this.state={
post:[this.props.route.params.posts]
}
and replace Object.keys with item.post
I want to paas "subjects" array from SubjectsScreen to MarkAttendanceScreen and display the array items as a FlatList.
Parent Component
export default class SubjectsScreen extends Component {
state = {
subjects: ["A", "B"]
};
render() {
return (
...
<MarkAttendanceScreen subjectsArray={this.state.subjects} />
);
}
}
Child Component
export default class MarkAttendanceScreen extends Component {
constructor(props) {
super(props);
this.state = {
subjects: []
};
}
componentDidMount() {
this.setState({ subjects: this.props.subjectsArray });
}
render() {
return (
<FlatList>
{ this.props.subjects.map((item, key)=>(
<Text key={key}> { item } </Text>)
)}
</FlatList>
);
}
}
Using props was giving error when using FlatList with map.
Works fine when extracting value directly from AsyncStorage.
export default class MarkAttendanceScreen extends Component {
state = {
subjects: [],
text: ""
}
componentDidMount() {
Subjects.all(subjects => this.setState({ subjects: subjects || [] }));
}
render() {
return (
<View>
<FlatList
data={ this.state.subjects}
renderItem={({item}) => {
return (
<View>
<Text> { item.text } </Text>
</View>
)
}}
keyExtractor={ (item, index) => index.toString()}
/>
</View>
);
}
}
let Subjects = {
convertToArrayOfObject(subjects, callback) {
return callback(
subjects ? subjects.split("\n").map((subject, i) => ({ key: i, text: subject })) : []
);
},
convertToStringWithSeparators(subjects) {
return subjects.map(subject => subject.text).join("\n");
},
all(callback) {
return AsyncStorage.getItem("SUBJECTS", (err, subjects) =>
this.convertToArrayOfObject(subjects, callback)
);
},
};
this.props.subjects does not exist, but you did set the state in componentDidMount. In the FlatList use this.state.subject.map.
render() {
return (
<FlatList>
{ this.state.subjects.map((item, key)=>(
// ^here
<Text key={key}> { item } </Text>)
)}
</FlatList>
);
}
You must use the same key name that you used while passing down data to child component e.g. in your case you used key subjectsArray here and You don't need to store this first in state and then use unless you want to update it later.
<MarkAttendanceScreen subjectsArray={this.state.subjects} />
So in your child component, it will be
<FlatList>
{this.props.subjectsArray.map((item, key)=>(
<Text key={key}> { item } </Text>
))}
</FlatList>
D. Smith is correct, you need to change that line to this.state.subjects.map But could also just remove the state variable from the Child Component and use the array directly from props.
export default class MarkAttendanceScreen extends Component {
constructor(props) {
super(props);
}
render() {
return (
<FlatList>
{ this.props.subjectsArray.map((item, key)=>(
<Text key={key}> { item } </Text>)
)}
</FlatList>
);
}
}
Update:
Flatlists need to be defined like this:
<FlatList
data={ this.props.subjectsArray }
renderItem={({item}) => {
return (
<Text> { item } </Text>)
)
}}
keyExtractor={(item, index) => index}
/>
or you can use it the way you have it and remove the flatlist like:
return this.props.subjectsArray.map((item, key)=>(
<Text key={key}> { item } </Text>)
)}
I have used this.props.maps as well as this.props.navigation which is showing an error:
this.props.navigation.navigate is undefined object
Trying to navigate to another page by rendering the firebase database but getting error but the same code i tried by simple creating a view and navigating to another page then it is working
export default class ItemComponent extends Component {
constructor(props) {
super(props);
// need to bind `this` to access props in handler
this._onEditLibrary = this._onEditLibrary.bind(this);
}
static propTypes = {
items: PropTypes.array.isRequired
};
_onEditLibrary=()=> {
this.props.navigation.navigate('EditLibrary');
};
render() {
return (
<View style={styles.itemsList}>
<TouchableOpacity onPress={this._onEditLibrary}>
{this.props.items.map((item, index) => {
return (
<View key={index}>
<ImageBackground source={item.Image} style={ { height:150, width:150}}>
<Text style={styles.itemtext}>{item.Name}</Text>
</ImageBackground>
</View>
)
})
}
</TouchableOpacity>
</View>
);
}
}
Need to navigate to another page
Try this out
export default class ItemComponent extends Component {
constructor(props) {
super(props);
// need to bind `this` to access props in handler
this._onEditLibrary = this._onEditLibrary.bind(this);
}
static propTypes = {
items: PropTypes.array.isRequired
};
_onEditLibrary=()=> {
this.props.navigation.navigate('EditLibrary');
};
render() {
return (
<View style={styles.itemsList}>
{this.props.items.map((item, index) => {
return (
<TouchableOpacity key={index} onPress={this._onEditLibrary}>
<ImageBackground source={item.Image} style={ { height:150, width:150}}>
<Text style={styles.itemtext}>{item.Name}</Text>
</ImageBackground>
</TouchableOpacity>
)
})
}
</View>
);
}
}
I have a dialog box that I want to present. I need an arrow function that allows me to call the callback prop that I have written as well as close the modal screen by the use of state. I am able to close it but not invoke the callbacks from the parent component
export class DialogBox extends PureComponent {
okButton = <Button type="text" title={t('action')} onPress={this.onOkPressed} />
cancelButton = <Button type="text" title={t('cancel')} onPress={this.onCancelPressed} />
confirmButtonBox = (
<Fragment>
{this.cancelButton}
{this.okButton}
</Fragment>
)
state = {
isVisible: this.props.isVisible,
}
onModalClose = () => {
this.setIsVisible(false)
}
onOkPressed = () => {
this.props.onOkPress()
this.onModalClose()
}
onCancelPressed = () => {
this.props.onCancelPress()
this.onModalClose()
}
setIsVisible (visible) {
this.setState({ isVisible: visible })
}
renderButtons (type) {
switch (type) {
case 'confirm':
return this.confirmButtonBox
case 'alert':
return this.okButton
default:
return this.okButton
}
}
render () {
const {
title, message, type,
} = this.props
return (
<Modal transparent animationType="fade" visible={this.state.isVisible}>
<View style={styles.container}>
<View style={styles.alertContainer}>
<View>
<Text>
<H3 style={{ fontWeight: 'bold' }}>
{title}
</H3>
</Text>
<Text>
{message}
</Text>
</View>
<View style={styles.buttons}>
{this.renderButtons(type)}
</View>
</View>
</View>
</Modal>
)
}
}
The way I need it to work is:
I have a container class external to this component which allows user to implement a callback method on Ok press and onCancle press.
class DialogBoxStoryContainer extends PureComponent {
// state = { isVisible: false, type: 'confirm' }
onOkPressed = () => {
// this.setState({ isVisible: false })
console.debug('on ok pressed')
}
onCancelPressed = () => {
// this.setState({ isVisible: false })
console.debug('on cancel pressed')
}
render () {
return (
<View>
<DialogBox
{...this.props}
onOkPress={this.onOkPressed}
onCancelPress={this.onCancelPressed}
isVisible="true"
type="confirm"
/>
I do not see the callbacks being executed here. What am i missing here?
Your code works for me. If your "Default Levels" in Chrome (I assume you are using Chrome) is not set for "Verbose", you can't see console.debug outputs. I don't know where this config is in Firefox or other browsers. So, if you are using another one just find this setting.
I know we can call the function like {this.props.onPress}, can we pass value using this callback too? Default object is passed but I want to pass a string value using this function. Is this possible, I'm posting my code to clear the situation.
import Cbuttons from './../utils/CustomButtons'
class MainScreen extends Component {
_onBtnClick = event => {
console.log("Click on Button");
}
render() {
return (
<View style={customStyles.mainContainer}>
<Cbuttons btnName="MainScreen" onPress={this._onBtnClick}/>
<Cbuttons btnName="ScreenTwo" onPress={this._onBtnClick}/>
<Cbuttons btnName="ScreenThree" onPress=
{this._onBtnClick}/>
</View>
);
}
}
export default MainScreen;
while inCustom Buttons clsss
class MyButtons extends Component {
constructor(props){
super(props);
this.state={btnName:this.props.btnName};
}
render(){
return(
<TouchableOpacity onPress={this.props.onPress} >
<Text style={yourStyles.buttonText}> {this.props.btnName}</Text>
</TouchableOpacity>
);
}
}
export default MyButtons;
I want to return btnName back via this.props.onPress
<Cbuttons btnName="MainScreen" onPress={ () => { this._onBtnClick(this.props.btnName)}/>
Turn that field into a function which calls the _onBtnClick function normally with a parameter.
Then you would reflect that in the _onBtnClick() method:
_onBtnClick = buttonName => {
console.log(`Click on Button ${buttonName}`);
}
This solved my problem, Thanks #mcpolo
class MyButtons extends Component {
render(){
return(
<TouchableOpacity onPress={()=>{this.props.onPress(this.props.btnName)}} >
<Text style={yourStyles.buttonText}> {this.props.btnName}</Text>
</TouchableOpacity>
);
}
}