I've got a button that calls a procedure onApproximateAgePress which fails to see 'this.data'.
<Button title="<20" onPress={onApproximateAgePress}/>
onApproximateAgePress () {
console.log('onApproximateAgePress') ; // outputs onApproximateAgePress
console.log(this.data) ; // outputs null
}
// Getter for "Immutable.js" state data...
get data() {
return this.state.data;
}
// Setter for "Immutable.js" state data...
set data(data) {
this.setState({ data });
}
state = {
data: fromJS({
showApproximateAgePicker: false,
...
}),
}
I have other components that have been wired up in a similar way but they do see this.data.
If I change the call to
<Button title="<20" onPress={(e)=>console.log(this.data) }/>
I get a log of with valid values.
Why would 'this.data' go out of scope?
Well in both the alternatives , there is one major difference , on the first approach you are just assigning a callback to the onPress Event , where as in second you are using arrow function.
So what does arrow function do? for starter it binds the lexical scope of 'this' ,in second case to the block where you are logging this.data
Read for More : Arrow Functions
so this you are referring in onApproximateAgePress() does not equal to current instance of this component, you should bind it.
or
Solution I : <Button title="<20" onPress={this.onApproximateAgePress.bind(this)}/>
Solution II : <Button title="<20" onPress={() => onApproximateAgePress()}/>
You should be able to access this and hence this.data
Related
I want to use a modal in my React Native app that ask the user to confirm his action.
The state looks like this:
state = {
dialogVisible: false,
confirmed: null
}
If the user confirms his delete action (turning confirmed to true), I want to execute my delete() method.
Delete method:
delete = () => {
const { deckName } = this.props.navigation.state.params
console.log('WAS CONFIRMED')
this.setState({
dialogVisible: false
})
this.props.navigation.navigate('Decks')
removeDeckFromStorage(deckName)
this.props.dispatch(removeDeck(deckName))
this.setState({
confirmed: null
})
}
noDelete = () => {
this.setState({
dialogVisible: false
})
this.setState({
confirmed: null
})
}
When the user confirmed his action, the modal closes, and the delete is done. Afterwards, I want to set confirmed back to null re-use it later.
On the other hand, if the user does not confirm the modal by clicking No, the noDelete() method should be called, which just closes the modal and sets confirmed back to null.
My problem is now that I get a warning saying:
Warning: Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state.
That is because I check for the state of confirmed inside the render() method:
const { confirmed } = this.state
if (confirmed){
this.delete()
}
else if (confirmed === false){
this.noDelete()
}
I did this because when I checked the state of confirmed inside the delete method right after setting the confirmed state to true, it always said null.
I put the check inside render because after the confirmed state is changed through the user input, the component is re-rendered and thus giving me the right state for the query.
The dialog buttons each change the current confirmed state when clicked:
positiveButton={{
title: "YES",
onPress: () => this.setState({confirmed: true})
}}
So, how can I check for confirmed after it was set but still outside of the render method to keep it pure?
You should never update the state in the render method. You should move your logic to the delete and noDelete functions instead.
I'm not sure how your modal is, however let's suppose it's something like this:
<View>
<TouchableOpacity onPress={this.delete}>
<Text>Delete</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.noDelete}>
<Text>No Delete</Text>
</TouchableOpacity>
</View>
And in the delete and noDelete you simply remove the setState({ confirmed }) since you're already calling the deletion from there.
Hi I need create function which have payload.
In Vuex I created:
const getters = {
[GettersTeam.GET_TEST](state) {
return state.teams;
},
[GettersTeam.GET_TEAM]: state => id => {
console.log("Run function!");
console.log(id);
return state.teams;
},
};
Next I using this function in component:
mounted() {
this.GET_TEAM(1);
},
methods: {
...mapGetters('TeamModule', [GettersTeam.GET_TEAM]),
},
Function this.GET_TEAM(1) nothing return. I thing the problem is with the name function [GettersTeam.GET_TEAM], but I don't know how I can named function with namespaced. Function this.GET_TEST() work correctly.
EDIT:
I moved function from methods to computed.
computed: {
...mapGetters('TeamModule', {
teamList: [GettersTeam.GET_TEAM],
}),
},
<template>
<div>
teamList: {{ teamList }}
</div>
</template>
But when I try using teamList in template Vue returned me this:
teamList: function (id) { console.log(id); return state.teams; }
You need to put mapGetters in your computed section, not methods:
computed: {
...mapGetters('TeamModule', [GettersTeam.GET_TEAM]),
},
https://vuex.vuejs.org/guide/getters.html#the-mapgetters-helper
That may seem slightly counter-intuitive given you're invoking it as a method but from the component's perspective it's still just a property. It just so happens that the property returns a function.
Update:
Based on the new question...
In your template you've got {{ teamList }}. That will be grabbing the value of the property this.teamList.
The property this.teamList is a computed property, so Vue will call the defining function behind the scenes. That defining function is created by mapGetters but it effectively just calls the store getter, passing it the relevant state object.
You've defined the getter like this:
[GettersTeam.GET_TEAM]: state => id => {
Ignore the bit in the brackets, that isn't important here. The key bit is the state => id => { part. There are two functions here, one being returned by the other.
Effectively it is equivalent to this:
[GettersTeam.GET_TEAM] (state) {
return function (id) {
console.log("Run function!");
console.log(id);
return state.teams;
}
}
So when you access the computed property you're just going to be invoking that outer function. It'll return the inner function, which is what you're seeing your template.
To get the value returned by the inner function you'd need to invoke it. e.g.:
{{ teamList(1) }}
I would also note that your current implementation of the getter just ignores the id. It isn't clear exactly what you're trying to do but I assume you're intending to implement a search based on the id to find a particular entry within state.teams.
Made a Codepen for you.
Your mapGetters call should be mapGetters([GettersTeam.GET_TEAM]) and your this.GET_TEAM(1); call should be this[GettersTeam.GET_TEAM](1); instead.
I still don't get why I'm getting an update depth exceeded on this specific case, i would appreciate if any help is given.
To give some insight.
I got a Parent and a Child (multi-list selector) component that I created.
This multi-list allows you to select multiple items and when modal is closed, I execute a callback that comes from Parent, with the list of items selected and update it from the Parent itself by doing setState.
On Parent's constructor I got the callback function like this:
Parent
this.onItemSelected = this.onItemSelected.bind(this);
This is the function above:
onItemSelected(updatedList) {
this.setState({selectedItemList: updatedList});
}
This is when I use it and pass it to Children.
renderModalMultiSelect = () => {
return (
<MultiSelect
items={this.state.itemList}
onItemSelect={ this.onItemSelected }
disabled={this.state.filters.type === 'all'}
isLoadingList={this.state.isLoadingList}
/>
)
}
Of course this is on Parent's render() function as { this.renderModalMultiSelect() }
Children
On this component, I handle the selected item list locally, is not on the State, so whenever I press on items, I just simply do a push on this local array.
When I close the modal, I run the parent props callback.
onClose = () => {
this.setState({ modalOpened: false }, () => {
// Optional callback
if (this.props.onItemSelect) {
this.props.onItemSelect(this.selectedItems);
}
})
}
Again, this function is used on children's render()
<Button onPress={ this.onClose } transparent>
<Icon name="md-arrow-back" style={ styles.headerIcon }/>
</Button>
Before this, I was passing a state from Parent to Children with the list of selected items, but it didn't seem right to do things like: this.props.selectedItemList.push(item) or is this fine to do?
Thanks and I hope I can understand what's going on here, it keeps throwing this error whenever I close the modal (onClose is called).
I have the following code:
export default class Testing extends Component {
state = ({
data: []
});
componentDidMount() {
this.setState({
data: this.props.values
});
console.log(this.state.posts); //prints empty but if I do
console.log(this.props.values); //prints the array correctly
}
Where is the error since I can print the props not the state?
Thanks
You're not storing anything in this.state.posts. Your initial state only contains data.
Also when you construct your initial state you should do it like this:
state = {
data: []
}
You do not need the ( ) around it.
If you are wanting to print a value from state as soon as you have stored it you must use the callback functionality of state. This is due to the fact that setState is asynchronous and takes time to set the value. Currently you are trying to read the value before it has been set, use the callback functionality like below.
this.setState({
data: this.props.values
}, () => console.log(this.state.data));
Here are some great articles on setState.
https://medium.learnreact.com/setstate-is-asynchronous-52ead919a3f0
https://medium.learnreact.com/setstate-takes-a-callback-1f71ad5d2296
https://medium.learnreact.com/setstate-takes-a-function-56eb940f84b6
you don't need the ( ) when you set the initial state because it is an object.
export default class Testing extends Component {
state = { //remove (
data: []
}; //remove )
Also worth noting, setState is an async function. You will not be able to getState directly after setState.
In order to get the state right away, you would provide a callback to setState() https://reactjs.org/docs/react-component.html#setstate
I am attempting to use Lodash's debounce on a Vue 2 method in order to only run once a user has stopped typing in an input field, but I am getting unexpected results:
INPUT FIELD
<input type="text" v-model='filter.user' placeholder="search" #keyup='dTest'>
METHOD
dTest() {
const d = _.debounce(() => {
console.log('hi');
}, 2000);
d();
}
However, 'hi' is being logged to the console on every keypress, with a two second delay.
thanks
Change dTest to:
dTest = _.debounce(() => {
console.log('hi');
}, 2000);
With your dTest, you are creating a new debounce function every time dTest is run. You are meant to create this function only once, like you see above, then call that function every time.