I'm looping through a native-base <Card dataArray={data} /> component rendering some components with Buttons. It was working alright (Listed all components as expected) but I soon added an onPress event to the Button and got an automatic onPress bug, weird enough it runs (clicks hence runs the bounded function) only once while components suppose to render with those buttons are many.
//- Inside constructor I bind testLogs
this.testLogs = this.testLogs(this);
//- Outside render...
testLogs(value) {
console.log(value);
}
//- Inside return of render()
<Card dataArray={devices}
renderRow={(theme) =>
<CardItem>
{(theme.picture) ?
<Thumbnail size={100} source={theme.picture} />:
<Thumbnail size={100} source={defaultImage} />
}
<Text style={{fontSize: 16}}> {theme.name} </Text>
<Button primary style={{marginRight: 10}}> Command </Button>
<Button success onPress={this.testLogs} > Edit </Button>
</CardItem>
}>
</Card>
I should also say all the rendered components don't run the onPress={this.testLogs} bound function when i click them after they render.
What could be triggering this? Or is loop rendering not the best approach to this?
Thank you.
Use onPress={this.testlogs.bind(this)}
Related
I'm using the Modal built into React Native (and specifically I'm using the React Native Paper variant). By default this seems to open in the middle of the screen. However if you're doing some text input in the Modal then it would be more useful if it opened either at the top of the screen, or was aware of the keyboard. However I can't find a way to get this to work.
My (simplified) modal code is:
<Portal>
<Modal visible={visibleModalNew} onDismiss={closeModalNew} contentContainerStyle={styles.modalContainer} >
<View>
<Title>New</Title>
<View>
<TextInput
mode="outlined"
label="Data"
style={{alignSelf:'center', width:'95%'}}
defaultValue={newData}
onChangeText={newData=> setNewData(newData)}
onSubmitEditing={() => handleDone()}
/>
<Button onPress={() => doSomething()}>Do something</Button>
</View>
</View>
</Modal>
</Portal>
Ah, figured out a way round. I wrapped the modal in a KeyboardAwareView, removed the visible prop from the modal, and then wrapped it all in a conditional render and put the visible prop there instead. Seems to work as hoped.
I am adding two props (textProp & imgProp) to my custom component, but I keep on getting this error <Image> component cant contain children. This is what I have soo far
function TextImg(textprop, imgprop) {
return(
<div>
<div>
<Text>{textprop.text}</Text>
</div>
<div>
<Image source={imgprop.imageUri}>!</Image>
</div>
</div>
);
}
Can anyone help me regarding this, Thanks!
Images (img) are considered empty elements and are self-closing, and required to be per the html spec.
https://developer.mozilla.org/en-US/docs/Glossary/Empty_element
The react native Image has the same restriction.
They can't wrap anything or have any children nodes. The "!" is the issue.
<Image source={imgprop.imageUri}>!</Image>
Try instead
<Image source={imgprop.imageUri} />
If you need to display an "!" then it'll have to be outside the image.
if you need to show "!" in image,
Try
<View>
<Image source={img} />
<Text
style={{
position: "absolute",
// some stylng
}}
>
!
</Text>
</View>
I have this application that i am writing in react-native, where i have this screen which displays around 50-100 images and some action buttons associated with them, including a pop-up menu(one associated with each of them). Is there a way that i can use same pop-up menu(same instance) for all images?
<View>
// react-native-paper Card Component
<Card style={styles.card}>
<Card.Content style={styles.cardContent}>
<Card.Cover
style={{ height: 60, width: 60 }}
source={
item.avatar ||
(item.gender === 'male'
? require('../../assets/male.jpeg')
: require('../../assets/female.jpeg'))
}
/>
<Caption style={styles.title}>{item.name}</Caption>
</Card.Content>
<Card.Actions>
<Avatar.Text
style={{ backgroundColor: 'skyblue' }}
size={24}
label={`#${item.id}`}
/>
// react-native-paper Menu Component
// can i somehow use a single component for all cards?
<Menu
visible={this.state.visible}
onDismiss={this._closeMenu}
anchor={
<IconButton
icon="menu"
theme={theme}
size={20}
onPress={() => console.log('Pressed')}
/>
}
>
<Menu.Item onPress={() => {}} title="Item 1" />
<Menu.Item onPress={() => {}} title="Item 2" />
<Divider />
<Menu.Item onPress={() => {}} title="Item 3" />
</Menu>
</Card.Actions>
</Card>
.
.
//same card multiple times
.
.
</View>
You can extract the Menu component into your own custom component and then reuse it in your cards. This means you only need to define your Menu once and then use that one component multiple times (which will create a separate instance of the Menu for each card, acting independently of each other).
You can also do the same for your Card component which means you don't have to define the same thing multiple times. Will make your code much cleaner and more useable (your methods you define in your components will only execute for that instance of the component, not on a global level as your above code will - e.g. this._closeMenu will only execute for the Menu instance that it's defined in)
Take a look here for how to go about extracting and reusing your components - https://caster.io/lessons/react-native-extracting-and-writing-react-native-components
Here is my phone screen I tried ScrollView with keyboardShouldPersistTaps, but it didn't work. I have a ScrollView for Autocomplete suggestions, and when user can types there, they should also be able to select from suggestions. However, without closing keyboard, it is not possible in my case. Here is my work
<ScrollView
scrollEnabled={false}
keyboardShouldPersistTaps={true}>
<View style={{ maxHeight: 220 }}>
<ScrollView style={Style.suggestionContainer}
scrollEnabled={true} >
{this.state.showOptions.map(this.renderSuggestions)}
</ScrollView>
</View>
</ScrollView>
.
.
.
private renderSuggestions(option: MultiInputQuestionOption) {
return (
<TouchableOpacity onPress={this.addSelection.bind(this, option)} >
<Text style={Style.suggestions}>
{option[this.props.titleKey]}
</Text>
</TouchableOpacity >
)
}
Is there any possible solution?
You need to pass the key keyboardShouldPersistTaps=‘handled’ on scroll view which contains the TextInput:-
<ScrollView keyboardShouldPersistTaps=‘handled’>
...
<TextInput />
</ScrollView>
And if you are having issue inside of a modal then You need to pass key keyboardShouldPersistTaps=‘handled’ on All scrollview which are in component stack for the screen. In the ancestors/parent of the Modal also.
Like in my case:
const CountryModal=(props)=>{
return(
<Modal
visible={props.visible}
transparent={false}
{...props}
>
<ScrollView keyboardShouldPersistTaps=‘handled’>
…
</ScrollView>
/>
)
}
In Parent class:
In the parent class where ancestors of modal is there. You need to pass key keyboardShouldPersistTaps=‘handled’`.
class Parent extends Component{
render(){
return(
<ScrollView keyboardShouldPersistTaps=‘handled’> // pass ‘handled’ here also
…
<CountryModal /> // Its the same modal being used as a component in parent class.
</ScrollView>
)
}
Try adding
keyboardShouldPersistTaps={'always'}
to the second ScrollView as well.
Use the 'handled' value for keyboardShouldPersistTaps property because the true value is deprecated. use the keyboardShouldPersistTaps in two ScrollViews and handle your keyboard state in somewhere else by using Keyboard.dismiss() function.
I just want to toggle SearchButton and SearchIcon , I use following code
searchBarButton() {
Actions.refresh();
this.setState({ showSearchBar: !this.state.showSearchBar });
}
render() {
if (this.state.showSearchBar) {
return (
<Header>
<View style={styles.searchHolder}>
<Item style={styles.searchBar}>
<Icon name="ios-search" />
<Input placeholder="Search" />
</Item>
<Button style={styles.searchButton} onPress={this.searchBarButton}>
<Text>Search</Text>
</Button>
</View>
</Header>
);
}
return (
<Header>
<Button onPress={() => this.searchBarButton()} transparent>
<Icon name="search" style={styles.bigblue} />
</Button>
</Header>
);
}
So basically It is very fast initially , But when my scene contains lots of items in flat List , There is like 1 to 2 seconds delay between toggle.I guess its due to re-rendering all items in page.
So How can I toggle this in more easier and efficient way without Re rendering whole page without using state
I think you have to hide one of them by using style prop.
Just render both first, toggle one of them to be hidden(by using state),
<Header>
<View style={[this.state.showSearchBar && styles.hidden]}>Button</View>
<View style=[{!this.state.showSearchBar && styles.hidden}]>Icon</View>
</Header>
do not remove them from virtual dom(I don't know what to call it in mobile) completely
I'd recommend you to grab some UI library. Take a look at this: https://react-bootstrap.github.io/components.html#utilities
You can just trow you your searchbar code in this
<Collapse in={this.state.showSearchBar}>
...
</Collapse>
And everything is taken care of very efficiently.
You just need to trow your button in an operator {!showSearhBar && <Component/>}
Also use react dev tools to check what re-renders