In React, why does adding state that is a number to prop that is a number results in string? - javascript

If I do the following:
this.setState( { skip: this.state.skip + this.props.PageSize } );
the result is a string, (e.g. "0555" when it tries to add 5 every click)
During debugging, it shows this.state.skip as a number, but this.props.PageSize as a string. However, the prop is defined as a number:
export interface IMyProps{
Description: string;
Context: WebPartContext;
Environment: string;
PageSize: number;
}
Do I always have to parse React props? Seems odd.
Edit: trying to do the following:
parseInt(this.props.Pagesize)
fails because, well obviously, you can't parse a number to an int, only a string.

Based on the details you provided, it looks like a logic issue but you can change your code like below to fix this issue
const { PageSize } = this.props;
this.setState(prevState => ({ skip: prevState.skip + parseInt(`${PageSize}`) }));
prevState.skip
We should use function inside setState when new state should be updated based on the current state.
parseInt(${PageSize})
This make sure that you are having string value and then parse it to Integer.
This won't be required if you make sure that number is passed instead of string

As commented by patrick:
Anything you pass inside the quote will be string.
myprop="1" // 1 is string here
myprop={1} // 1 is number here
So, you have to use curly brace to use number or variable but not quote.
Hint: You may also use the following to fix your issue:
this.setState( { skip: this.state.skip + +this.props.PageSize } );

Related

StencilJs/Jsx: render HTMLElements in nested component

This is my component:
#Component({
tag: "my-alert-list",
styleUrl: "alert-list.scss",
shadow: true,
})
export class AlertList {
#State() alertList: object[] = [];
#Method()
async appendAlert(
type: string,
message: string,
htmlContent: object,
canClose: boolean = false,
closeDelay: number
) {
let alertBoxElement = (
<my-alert-box
alert-type={type}
message={message}
can-close={canClose}
close-delay={closeDelay}
opened
>
{htmlContent}
</my-alert-box>
);
this.alertList = [
...this.alertList,
alertBoxElement
]
}
render() {
return (
<Host>
{this.alertList}
</Host>
);
}
}
The method appendAlert aims to append a new my-alert-box element to the list of alerts.
In same case i don't want to pass a simple text to the my-alert-box but some HTML block.
(my-alert-box has a receiver slot element and i verified that it works).
I tried to achieve this with the htmlContent variable as you can see, but of course it doesn't work if i do:
$('#alertlist')[0].appendAlert(type='info',message='', htmlContent=document.createElement('div'))
I receive the error:
[STENCIL-DEV-MODE] vNode passed as children has unexpected type.
Make sure it's using the correct h() function.
Empty objects can also be the cause, look for JSX comments that became objects.
Any idea on how can i achieve this?
It's not possible like this because JSX works differently. You could pass the htmlContent as a string and use innerHTML on my-alert-box but it's dangerous (XSS).
Ionic's ion-alert has the same limitation with the message prop... see https://ionicframework.com/docs/api/alert#properties which has a link to https://ionicframework.com/docs/techniques/security, and there they explain how they do some basic DOM sanitization (#ionic/core is also built with Stencil).

type of event.target.value should be changed to integer in react

I have an input field and When we enter the value in the input field I am updating the state with the entered value using event.target.value. By default the event.target.value be a string. Can we convert that into an integer ?
const func=(props)=>{
return(
<div>
<input type="text" onChange={props.change} value={props.value}/>
</div>
)};
// handler function
changeHandler =(event)=>{
this.setState({data:event.target.value})
};
My state has integer value that i assigned to Zero (data:0). So while updating the state using changeHandler function data becomes string.I want to typecast the event.target.value to the integer.
Actually there is a more direct way. You can simply get the value as a number without transforming it :
event.target.valueAsNumber
Also for edge cases use it like const value = isNaN(e.target.valueAsNumber) ? null : e.target.valueAsNumber;
Here is a syntactic sugar version of the other answers which will also attempt to convert your value to an int (or return NaN) in base 10 :
this.setState({data: +event.target.value });
Solution 1: (I highly recommend)
console.log($event.target.valueAsNumber) // Use valueAsNumber instead of value
Note: $event.target.valueAsNumber is not avilable for few input elements such as select, options etc. In that case use Solution 2.
(#Mads Hjorth)
Solution 2:
use parseInt() or parseFloat() or Number()
var integer = Number('613613');
// var integer = parseFloat('613613');
// var integer = parseInt('613613', radix); // radix is option parameter
Why this error?
$event.target.value will always be a string or undefined.
$event.target.value is only available for input type element. For example, if I click a div then $event.target is a div that does not have value property.
You can do this by parsing the string to an integer:
this.setState({data: parseInt(event.target.value, 10) });
You can do that with parseInt function.Documentation on this
this.setState({data: parseInt(event.target.value, X)})
Where X is your radix (per documentation)
I was able to do it using parseFloat(). In your case, you can try
changeHandler = event => {
this.setState({ data: parseFloat(event.target.value) });
};
But make sure to only use this handler when numbers will be added or else you get an error NaN in state.data
function changeHandler(event: any) {
let { name, valueAsNumber, value } = event.target;
setStateVariable((prevState: stateVariableInterface| undefined) => ({
...prevState,
[name]: Number.isNaN(valueAsNumber) ? value : valueAsNumber,
}));
}
event.target.valueAsNumber works.

object's number property is converted to string in Angular2

I have a model with two properties one of which is a number.
export class Ingredient
{
constructor(public name:string,public amount:number)
{
}
}
However every time I try to add to the amount I actually get concatenation. The weird thing is that when I try to do parseInt to the value I get the error I cannot pass number to parseInt but typeof returns string for the property.
addIngredient(ingredient: Ingredient)
{
let ingredientInList=this.ingredientInList(ingredient);
//alert(ingredientInList);
if(ingredientInList!==false)
{
// alert(typeof(this.ingredients[ingredientInList].amount));
this.ingredients[ingredientInList].amount=this.ingredients[ingredientInList].amount + ingredient.amount;
}
else
{
//alert(typeof(ingredient.amount));
this.ingredients.push(ingredient);
}
this.ingredientsChanged.emit(this.ingredients.slice());
}
So when I run the above code the amount next to an ingredient gets concatenated to the previous amount (assuming it has found a similar ingredient already).
Any ideas?
Please make sure that type of both "amount" is number not string.
otherwise, you can use this below code to parse the number-
this.ingredients[ingredientInList].amount = parseInt(this.ingredients[ingredientInList].amount) + parseInt(ingredient.amount);

Increasing count on click for custom Object

I'm working with a custom Library in React, where you can add emojis, And I'm trying to make a counter variable to the object, which increases each time a user clicks on it.
The point is to make it into an array, of several emojis, but so far, I'm trying to make it work with only one.
So I have a condition rather the emoji should be shown or not
{
this.state.showEmoji &&
<div className="emoji">
<Emoji
onClick={this.increment}
emoji={{ id: this.state.emoji.id, skin: 1, }}
size={25}
/>
<p>{this.state.emoji.count}</p>
</div>
}
Inside I render my Emoji along with the counter, which determinates how many times the emoji has been rendered/clicked
I'm not sure if I should make an anonymous function or make a handler, I tried out with the handler
I have made a custom emoji object in my state (which will eventually be an array of emoji objects)
emoji: {
id: '',
count: 0,
}
Along with my increment handler method:
increment = (emoji) =>{
console.log(emoji.id);
console.log(this.state.emoji.id);
this.setState({
count: this.state.emoji[emoji.id].count++
});
}
I successfully console log the emoji objects state id and then passed in emoji object, and they match.
But when I try to mutate the state I get this error:
TypeError: Cannot read property 'count' of undefined
Why can't I access the object with the id in this case?
increment = (emoji) =>{
const { emoji } = this.state; // isn't that more readable?
const _emoji = {
...emoji,
count: emoji.count + 1
} //this will create a copy of your emoji object.
// use +1 instead of ++ to make sure you are keeping the original count value as it is, 'PURE PROGRAMMING'
this.setState({ emoji: _emoji });
}
Please take a look at this sandbox code, it may help with managing the array of emojis as well.

immutable.js confused when use get() method

I'm using the immutable.js and redux in project, and I found an quite strange issue.
here is the code used in selector:
{
dealDetail : dealDetails.get(id.toString()).toJS(),
dealTrackLog : dealTrackLogs.get(id).toJS()
}
First, the id is Number, in detail, I must pass string of id, and in trackLogs, on the contrary, it must be Number, otherwise will cause error, "cannot read property toJS() of undefined"
and I think the problem maybe in reducer, here is the code:
// dealDetailReducer
// const initialStateOfDealDetail = fromJS({})
let details = {}
action.data.details.map((detail) => {
details[detail.id] = detail
})
return state.merge(fromJS(details))
...
// dealTrackLogsReducer
// initialStateOfDealTrackLogs = fromJS({})
if (state.get(action.data.id)) {
// has id in state, update
return state.withMutations(s =>
s.update(
action.data.id,
trackLog => trackLog.merge(fromJS(action.data.trackLogs))
)
)
}
// no id in state, just set, id : data
return state.set(action.data.id, fromJS(action.data)
so, I'm hard to understand why and when to pass a Number/String ?
First line
let details = {}
You are using regular object for details state. Objects coerce to string keys.
The second case you are using immutablejs operation that preserve the key type.

Categories