How to call a class and setState in one onClick(ReactJS) - javascript

I'm pretty new to React and I was wondering how I could call a function inside a class (so like this.handleChange) and an arrow function with a setState inside within one onClick of a button.
I've tried using commas and && in between the 2 lines of code.
<button name="Plus" onClick={() => this.setState({ Operator: 'plus' }) && this.handlePlus}>+</button>
The above code is inside the render and return.
The expected result is that the code calls the function and changes the state.Instead it just changes the state(so only does the first part).
Please help, thanks in advance!

setState() has an optional second parameter that is a function that will be invoked once the state has been set. You could do:
this.setState({ Operator: 'plus' }, this.handlePlus);
You can also use the componentDidUpdate lifecycle:
componentDidUpdate(prevProps, prevState) {
if(this.state.Operator === 'plus' && prevState.Operator !== 'plus') {
this.handlePlus();
}
}

< button name = "Plus"
onClick = {
() => this.setState({
Operator: 'plus'
}, () => this.handlePlus())
} > + < /button>
this would work fine.or
if you are looking
for something like this....
you can handle multiple buttonClick event like this
<
button name = "Plus"
value = "yourValue"
onClick = {
this.handleChange
} > + < /button>
handleChange = (e) => {
const {
name,
value
} = e.target;
switch (name) {
case 'Plus':
this.setState({
[name]: value
});
break;
default:
//enter code here
break;
}
}

Just add the this.setState({ Operator: 'plus' } within the handlePlus function.

Related

Call a function inside const React/Typescript

In my application, I want to conditionally render something, so I made a function getItem which I want to call in my custom Tooltip, const CustomTooltip.
How can I call the function with the return of my custom tooltip? Currently, it render getState("A"),
getState("B"),
getState("C"), on the tooltip. See code below:
const numberStates = 3;
function getState({payload}: TooltipProps<ValueType, NameType>, state: string ){
if(payload){
for(let i = 0; i < numberStates; i++){
if(payload[i].dataKey == state){
return <p>{ payload[i] } : { payload[i].value }</p>
}
}
}
return null;
}
const CustomTooltip = ({ active, payload, label}: TooltipProps<ValueType, NameType>) => {
if(active && payload && payload.length){
return (
<div className = "custom-tooltip">
getState("A")
getState("B")
getState("C")
</div>
);
}
return null;
}
You need to surround your calls to getState in brackets:
const CustomTooltip = ({ active, payload, label}: TooltipProps<ValueType, NameType>) => {
if(active && payload && payload.length){
return (
<div className = "custom-tooltip">
{getState("A")}
{getState("B")}
{getState("C")}
</div>
);
}
return null;
You should expect to use this syntax if you're trying to utilize any javascript functionalities within the JSX.
More information can be found here regarding functions in react. You can scroll down to the "Example: Passing params using arrow functions" section and see an example of how brackets are necessary for using a map on the state.

use of lodash debounce function

I am using a debounce function in my react native project. It gets triggered after user enters 3 characters but it is triggering after 2 sec instead of the delay i assigned to it.
constructor() {
this.init()
this.hitSearchApi = debounce(() => {
log('inside if is called debounce')
this.getStudentTableData(() => this.updateFetchingStatus(true))
this.updateSearchLoaderStatus(false)
this.updateFetchingStatus(false)
}, 100)
}
I had created my debounce function inside the store constructor like this.
#action
onChangeSearchText = (searchText) => {
if (get(searchText, 'length', 0) > 2) {
log('inside search text if condition')
this.updateSearchLoaderStatus(true)
this.hitSearchApi.cancel()
// this.updateSearchLoaderStatus(true)
log('before hit search api')
this.hitSearchApi()
// fetch student list on search basis
} else if (get(searchText, 'length') === 0) {
this.setStudentListData({})
this.updateFetchingStatus(true)
this.resetSearchData()
}
this.searchText = searchText
}
This is my onChange text triggered, which is getting called on textinput onChange event.
Please help me out in this. What am I doing wrong here?

Checking a range of checkboxes between 2 boxes

I have a table of rows, each row has a checkbox. I have built a function that detects if the shift key had been pressed then, if it has then once 2 checkboxes are checked it will check the boxes between them.
The function works to some degree, however for some reason I have to check a third box to tick the boxes in-between.
How do I alter the code so it checks the boxes on the second check and not have to check a third?
Thanks in advance.
Below is my code.
Vue Data:
data: () => ({
keycheck: false,
checkRows: []
})
Created:
created() {
window.addEventListener('keydown', e => {
if (e.keyCode === 16) {
this.keycheck = true
console.log('The shift key is being held down...')
}
})
window.addEventListener('keyup', e => {
if (e.keyCode === 16) {
console.log('Upper')
this.keycheck = false
this.checkRows = []
//console.clear();
}
})
},
methods: {
checkbox(key) {
if (this.keycheck) {
this.checkRows.push(key)
if (this.checkRows.length === 2) {
console.log(this.checkRows)
for (let i = this.checkRows[0]; i <= this.checkRows[1]; i++) {
let bData = this.displayed_array
bData[i]['rowCheck'] = true
console.log('test')
}
}
}
},
},
There doesn't seem to be anything wrong with the code. However, right now if you're not holding shift, the first click is not registered in the checkRows variable. So you have to hold shift on the first click for it to work in two clicks.
if (this.keycheck) {
this.checkRows.push(key);
I replicated it in this codepen: https://codepen.io/CodingDeer/pen/pozbadW
FYI it's also better to set the array to empty using this.checkRows.length = 0; because it doesn't make a copy of the array.
I figure this out. By adding this.$forceUpdate() it updates the data. This was previously done by the third click.
methods: {
checkbox(key) {
if (this.keycheck) {
this.checkRows.push(key)
if (this.checkRows.length === 2) {
console.log(this.checkRows)
for (let i = this.checkRows[0]; i <= this.checkRows[1]; i++) {
let bData = this.displayed_array
bData[i]['rowCheck'] = true
console.log('test')
this.$forceUpdate()
}
}
}
},

Select in react does not reflect the state changes

Something weird is happening when I try to us select in reactjs.
Here is my code:
onDropDownChange=(e)=>{
let val = this.props.contactUsReducer.contactUsList.filter(function(item) {
return item.topic == e.target.value
});
let key= e.target.value;
let name= e.target.name;
console.log("key "+key+" val: "+val[0].displayName+" name:"+name);
this.setState(prevState => {
return ( {...prevState, [name]:key, displayName: val[0].displayName})
}, function () {
console.log(this.state);
});
}
and in my render I have
<select type="select" className="text-input flex-row-right-item" onChange={this.onDropDownChange} name="topic" value={this.state.displayName}>
{this.createSelectItems(this.props.contactUsReducer.contactUsList)}
</select>
Also here is my helper function:
createSelectItems=(itemsList)=> {
let items = [];
for (let i = 0; i < itemsList.length; i++) {
items.push(<option key={itemsList[i].topic} value={itemsList[i].topic}>{itemsList[i].displayName}</option>);
}
return items;
}
Now when I try to change the select box nothing will change in the UI so select box does not show the updated selection but I clearly see in the state that the state has been updated. Why the changes does not get reflected in select box.
Any idea?
For some reason you are supplying a function to your setState function. I personally find making a copy of the state and setting the properties to work better.
onDropDownChange = e => {
let val = this.state.myArr.filter(function(item) {
return item.topic === e.target.value;
});
let key = e.target.value;
let name = e.target.name;
console.log(
"key " + key + " val: " + val[0].displayName + " name:" + name
);
let prevState = { ...this.state };
prevState[name] = key;
prevState["displayName"] = val[0].displayName;
this.setState({ ...this.state, prevState });
console.log(this.state);
};
Change value set to displayName in your setState as,
this.setState(prevState => {
return ( {...prevState, [name]:key, displayName: key})
}, function () {
console.log(this.state);
});
Because the value prop should have the value of the selected option
The value on the select should be one of the values on the options tags, but as values on those options you're mapping the topic but you made value={this.state.displayName} on the select tag ?
if you replace it with value={this.state.topic} it will work since it uses the same data mapping.
here is a codesandbox exp.

Component doesn't update after setState

I use a dictionary to store the likes of posts in every card.
constructor(props) {
super(props);
this.state = {
like_dict: {}
};
this.likeClicked = this.likeClicked.bind(this)
}
I have a like button on every card and the text denotes the number of likes.
<Button transparent onPress={() => {this.likeClicked(poid, 0)}}>
<Icon name="ios-heart-outline" style={{ color: 'black' }} />
</Button>
<Text>{this.state.like_dict[poid]}</Text>
The likedClicked function looks like this. I set the state of like_dict, but the text above won't rerender.
likeClicked(poid, liked){
var like_dict_tmp = this.state.like_dict
if (liked){
like_dict_tmp[poid] -= 1
}else{
like_dict_tmp[poid] += 1
}
this.setState({
like_dict: like_dict_tmp
})
}
One of the key principles of React is never mutate the state directly.
When you do var like_dict_tmp = this.state.like_dict, like_dict_tmp is referencing the same object in the state so altering like_dict_tmp will mutate the state directly, so the subsequent setState will not update the component.
You can create a shallow copy with var like_dict_tmp = { ...this.state.like_dict } or replace the whole function with:
this.setState((prevState) => ({
like_dict: {
...prevState,
[poid]: (prevState[poid] || 0) + (liked ? 1 : -1),
},
}));
You need to copy the state before modifying it. What you are doing is just creating a link to the state in like_dict_tmp (either use what I am doing below, or use concat with an empty array):
var like_dict_tmp = this.state.like_dict.concat([])
likeClicked(poid, liked) {
var like_dict_tmp = this.state.like_dict.slice()
if (liked) {
like_dict_tmp[poid] -= 1
} else {
like_dict_tmp[poid] += 1
}
this.setState({
like_dict: like_dict_tmp
})
}
Also, {} is an object in JS, and is not typically called a dictionary

Categories