Getting the Id of a react-native element in event handler - react-native

How to get the Id of the element in onPress event handler.
I am adding elements dynamically and wants to know in the event handler of onPress of these elements to store in the state which elements are clicked.
Here is the code i have
export default class App extends Component {
constructor(props){
super(props);
this.getElements= this.getElements.bind(this);
this.selectElement = this.selectElement.bind(this);
}
componentWillMount(){
this.state = {
noOfElements :10
}
}
selectElement(e,key){
console.log('selectElement() : key=',key);
}
getElements(){
let elements =[];
for(let index=0;index<this.state.noOfElements;index++){
elements.push(
<View key={'View_'+index} style={{flex:1}}>
<Button
key={'View_'+index}
id={index}
onPress={(e,index) => {this.selectElement(e,index)}}
title={'Button-'+index}
/>
</View>
);
}
return elements;
}
render(){
let elements = this.getElements();
return(
<View style={styles.container}>
<Text>Test</Text>
{elements}
</View>
);
}
}
I tried just passing the key like
onPress={(index) => {this.selectElement(index)}}
with no success..
Not sure what i am doing wrong.

The way you have it, i think index would come up undefined, just remove index as an argument in your onPress so it grabs index from the for loop. Also you can prob refactor it using map.
onPress={(e) => this.selectElement(e,index)}

Changed the event handler as below and it is working fine now.
onPress={this.selectElement.bind(this,index)}
and the function now just accepts the index
selectElement(key){
console.log('selectElement() : Index=',key);
}

Related

React Native ios Switch in FlatList not toggling after value changed

I am trying to toggle ios Switch in react native. But the switch comes back to initial position as soon as I change it.
What I have:
class ABC extends Component {
constructor(props) {
super(props)
this.state = {
obj: []
}
}
fetch(){
// fetch something from remote server, set it to state object array
}
setStatus(id, value){
var temp = [...this.state.obj]
temp.map((t) => {
if (t.id == id) {
t.flag = value
}
})
this.setState({ obj: temp })
}
render() {
return (
<View>
<FlatList
data={this.state.obj}
renderItem={({ item }) =>
<View>
<Text>{item.name}</Text>
<Switch
onValueChange={(val) => this.setStatus(item.id, val)}
value={item.flag}
/>
</View>
}
keyExtractor={({ id }, index) => id.toString()}
/>
</View>
);
}
}
I logged the before and after value of obj state and they seem to update. Should the FlatList be rendered again (like a web page refresh) ? Or is there something I am missing ? Searched SO for answers, couldn't find my mistake.
Flatlist has a prop called extraData.
This prop tells Flatlist whether to re-render or not.
If data in extraData changes then flatlist re-renders based on new data provided in data prop.
So whenever you need to re-render flatlist just change something in extraData.
Best way is to pass state toextraData which is passed to Data.
So, just pass extraData={this.state.obj}.
there also other way called forceUpdate.
you can call this.forceUpdate().
but this is not recommended because this will render not only flatlist but entire component in which you are calling this.

react native, undefined is not an object (evaluating 'this.state.thing = input')

I am trying to set the onSubmitEditing function of a TextInput object to a custom function, here is my code:
export default class Component4 extends Component {
constructor(props) {
super(props);
this.state = {thing: 'asdf'};
this.func = this.func.bind(this);
}
func(input){
this.setState({thing: input.target.value});
// I will eventually do more complicated stuff
}
render(){
return (
<View style={{padding: 30}}>
<TextInput placeholder="default" onSubmitEditing={this.func}/>
<Text>{this.state.thing}</Text>
</View>
);
}
}
I would like the content of the TextInput to be passed to the function 'func' so that it can change the state of 'thing'. I realize I can just use an arrow function to achieve this and skip having function entirely however like it says in the comment in func I intend to add more complex behaviour there. Thanks for the help
When you declare your function that way it doesn't have access to this because of scoping. Use es6 fat function to give it access to this. Also use setState function instead of direct assignment
func = (input) => {
this.setState({thing: input});
//more complicated stuff here
};
Also change TextInput to use onChange instead of onSubmitEdit
You have to bind your methods to the constructor. You also need a method/function to handle text changes as well as one to handle collecting a result. edit: I guess now that I understand what you're going for, the button was unnecessary.
export default class Component4 extends Component {
constructor(props) {
super(props);
this.state = {myInput: '', myResult: ''};
this.onChange = this.onChange.bind(this);
this.onPress = this.onPress.bind(this);
}
onChange(input){
this.setState({myInput: input.target.value});
// I will eventually do more complicated stuff
}
onPress() {
this.setState({myInput: '', myResult: this.state.myInput});
}
render(){
return (
<View style={{padding: 30}}>
<TextInput name='myInput' placeholder="default" onChange={this.onChange}/>
<Text>{this.state.myResult}</Text>
<Button onPress={this.onPress} title='Click me!' />
</View>
);
}
}

react-native scrollView - scrollToEnd - on Android

I'm trying to call a function that will fire upon onFoucs on TextInput that will scroll the scrollView all the way down (using scrollToEnd())
so this is my class component
class MyCMP extends Component {
constructor(props) {
super(props);
this.onInputFocus = this.onInputFocus.bind(this);
}
onInputFocus() {
setTimeout(() => {
this.refs.scroll.scrollToEnd();
console.log('done scrolling');
}, 1);
}
render() {
return (
<View>
<ScrollView ref="scroll">
{ /* items */ }
</ScrollView>
<TextInput onFocus={this.onInputFocus} />
</View>
);
}
}
export default MyCMP;
the component above works and it does scroll but it takes a lot of time ... I'm using setTimeout because without it its just going down the screen without calculating the keybaord's height so it not scrolling down enough, even when I keep typing (and triggering that focus on the input) it still doesn't scroll all the way down.
I'm dealing with it some good hours now, I did set the windowSoftInputMode to adjustResize and I did went through some modules like react-native-keyboard-aware-scroll-view or react-native-auto-scroll but none of them really does the work as I need it.
any direction how to make it done the right way would be really appreciated. thanks!
Rather than using a setTimeout you use Keyboard API of react-native. You add an event listener for keyboard show and then scroll the view to end. You might need to create some logic on which input is focused if you have more than one input in your component but if you only have one you can just do it like the example below.
Another good thing to do is changing your refs to functional ones since string refs are considered as legacy and will be removed in future releases of react. More info here.
class MyCMP extends Component {
constructor(props) {
super(props);
this.scroll = null;
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow.bind(this));
}
componentWillUnmount () {
this.keyboardDidShowListener.remove();
}
_keyboardDidShow() {
this.scroll.scrollToEnd();
}
render() {
return (
<View>
<ScrollView ref={(scroll) => {this.scroll = scroll;}}>
{ /* items */ }
</ScrollView>
<TextInput />
</View>
);
}
}
export default MyCMP;
If you have a large dataset React Native docs is telling you to go with FlatList.
To get it to scroll to bottom this is what worked for me
<FlatList
ref={ref => (this.scrollView = ref)}
onContentSizeChange={() => {
this.scrollView.scrollToEnd({ animated: true, index: -1 }, 200);
}}
/>

React Native: Updating state in onLayout gives "Warning: setState(...): Cannot update during an existing state transition"

I have a component in React Native which updates it's state once it knows what size it is.
Example:
class MyComponent extends Component {
...
render() {
...
return (
<View onLayout={this.onLayout.bind(this)}>
<Image source={this.state.imageSource} />
</View>
);
}
onLayout(event) {
...
this.setState({
imageSource: newImageSource
});
}
...
}
This gives the following error:
Warning: setState(...): Cannot update during an existing state transition (such as within render or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to componentWillMount.
I guess the onLayout function is called while still rendering (which can be good, the sooner the update, the better). What is the correct way to solve this problem?
Thanks in advance!
We got around this by using the measure function, you will have to wait until the scene is fully complete before measuring to prevent incorrect values (i.e. in componentDidMount/componentDidUpdate). Here's an example:
measureComponent = () => {
if (this.refs.exampleRef) {
this.refs.exampleRef.measure(this._logLargestSize);
}
}
_logLargestSize = (ox, oy, width, height, px, py) => {
if (height > this.state.measureState) {
this.setState({measureState:height});
}
}
render() {
return (
<View ref = 'exampleRef' style = {{minHeight: this.props.minFeedbackSize}}/>
);
}
Here is a solution from documentation for such cases
class MyComponent extends Component {
...
render() {
...
return (
<View>
<Image ref="image" source={this.state.imageSource} />
</View>
);
}
componentDidMount() {
//Now you can get your component from this.refs.image
}
...
}
But for my opinion it's better to do such things onload

ReactNative / Switch Component: onValueChange

I've trying to set up a change event if someone modifies a switch component. The approach is to design a view that contains multiple switches and allows the user to set the state per each notification that will end up in a POST api-call. Futher, I'd like to load the initial values from a api-call.
How can I access the state (weather it's checked / unchecked) in my onChangeFunction? And how can I get an element using their ID or name? (same as in HTML/CSS with #mySwitch.setValue(true)?
Given code:
class Settings extends Component {
onChangeFunction(type, props) {
Alert.alert("changed", "==> " + props.state)
}
render() {
return (
<View style={styles.container}>
<Switch onValueChange={this.onChangeFunction.bind(this, "TASK_CREATED", this.props)} value={this.state} />
</View>
);
}
}
You have a mess there between the propsand the state concept. You can do:
class Settings extends Component {
state = {
taskCreated: false,
};
onChangeFunction(newState) {
this.setState(newState, () => Alert.alert("Changed", "==> " + this.state));
}
render() {
return (
<View style={styles.container}>
<Switch onValueChange={(value) => this.onChangeFunction({taskCreated: value})}
value={this.state.taskCreated}
/>
</View>
);
}
}
Notice that this.setState is asynchronous so you can safely read its value using the callback that the method provides.