Can someone tell me what's wrong with my code? I am not able to get event.target.name even though I am assigning value to name property
handleSectionDObservation = event => {
if (event.target.value === "Observation" && event.target.name !== "Observation") {
this.setState({
...this.state,
CalcNoOfObs2: this.state.CalcNoOfObs2 + 1,
[event.target.name]: event.target.value
});
console.log([event.target.name])
} else if(event.target.name === "Observation") {
this.setState({
...this.state,
CalcNoOfObs2: this.state.CalcNoOfObs2 > 0 ? this.state.CalcNoOfObs2 - 1 : 0,
[event.target.name]: event.target.value
});
console.log([event.target.name])
};
}
The setState function will not update your values synchronously, your state will not be changed right away. The second parameter of it allows you to give a callback function triggering when the state has been mutated.
You also do not need to update all the state values at once, the one that you give are the only one that are going to be affected. And if you need to use the old state values, you should use the callback version of setState :
this.setState(oldState => ({
CalcNoOfObs2: oldState.CalcNoOfObs2 > 0 ? oldState.CalcNoOfObs2 - 1 : 0,
[event.target.name]: event.target.value
}), () => { console.log(this.state[event.target.name]) });
The whole function can also be reduced to the following to avoid repetitions :
handleSectionDObservation = event => {
if(event.target.name !== "Observation" && event.target.value !== "Observation") return;
const CalcNoOfObs2 = event.target.name === "Observation" ?
this.state.CalcNoOfObs2 > 0 ? this.state.CalcNoOfObs2 - 1 : 0 :
this.state.CalcNoOfObs2 + 1;
this.setState(oldState => ({
CalcNoOfObs2,
[event.target.name]: event.target.value
}), () => { console.log(this.state[event.target.name]) });
console.log([event.target.name]);
}
Related
I learning design ui with react library. But I don't know what happended in my code.
handleIncrement = () => {
this.setState({
...this.state,
quantity: this.state.quantity + 1
});
console.log(this.state);
document.getElementsByClassName("Counter-Order")[0].innerHTML++;
};
handleDecrement = () => {
this.setState({
...this.state,
quantity: this.state.quantity > 1 ? this.state.quantity - 1 : 1
});
if (this.state.quantity > 1) {
document.getElementsByClassName("Counter-Order")[0].innerHTML--;
}
};
Result image
Please have a look I hope it's helpful
Thanks
handleIncrement = () => {
this.setState({
...this.state,
quantity: this.state.quantity + 1
},()=>{
console.log(this.state);
document.getElementsByClassName("Counter-Order")[0].innerHTML++;
});
};
handleDecrement = () => {
this.setState({
...this.state,
quantity: this.state.quantity > 1 ? this.state.quantity - 1 : 1
},()=>{
if (this.state.quantity > 1) {
document.getElementsByClassName("Counter-Order")[0].innerHTML--;
}
});
};
This is the intended behaviour. The set state updates the state after the function has executed since it's an asynchronous function.
So actually what happens is.
The setState is called.
Console log happens.
State updates.
So to check the state after setState use the 2nd parameter (callback) in the set state.
this.setState(
{ ...this.state,
quantity: this.state.quantity + 1 },
() => console.log(this.state
);
You are violating the main idea of React by directly accessing DOM like document.getElementsByClassName("Counter-Order")[0].innerHTML++;
Ideally You should have something like this in your render function.
render() {
return <div className="Counter-Order">{this.state.quantity}</div>;
}
setState is an asynchronous function.
React internally waits for the best moment to change the state and re-render the component.
So the new state value isn't available immediatly after executing setState. That's why in your case your console.log still shows the previous state value.
I was wondering how I would go about creating a new TextInput line when I press enter. So like you would have with a checklist. Something like this:
[TextInput line one]
and when I press on enter
[TextInput line one]
[TextInput line two with focus]
Another enter
[TextInput line one]
[TextInput line two]
[TextInput line three with focus etc]
Thanks for all the help
Here is an acceptable solution for you. I have used currying to create dynamic handler for TextInput event listener. You can check my solution online on this link.
class MyComponent extends Component {
state = {
inputValues: [''],
currentIndex: 0
}
inputRefs = []
handleSubmitEditting = index => () => {
if (this.state.inputValues[index + 1] === undefined) {
this.setState({
currentIndex: this.state.currentIndex + 1,
inputValues: [...this.state.inputValues, ''] // mutate state (inputValues) & add an empty string
})
} else {
const ref = this.inputRefs[index + 1]
this.setState({
currentIndex: index + 1
}, () => {
if (ref) {
ref.focus();
}
})
}
}
handleChangeText = index => rawText => {
const nextInputValues = [...this.state.inputValues] // always mutate state
nextInputValues[index] = rawText.replace('\n', '')
this.setState({ inputValues: nextInputValues })
}
handleRef = index => ref => {
this.inputRefs[index] = ref
if (index === this.state.currentIndex && ref && !ref.isFocused()) {
ref.focus();
}
}
render() {
const { inputValues } = this.state;
return (
<View>
{inputValues.map((value, index) => (
<TextInput
key={index}
ref={this.handleRef(index)}
value={value}
onSubmitEditting={this.handleSubmitEditting(index)}
onChangeText={this.handleChangeText(index)}
/>
))}
</View>
)
}
}
I am implementing a search filter in my app and need to persist data between browser refreshes.
Here is my code:
class App extends Component {
state = {
data: shop,
direction: {
price: "asc",
title: "asc"
},
searchTitle: "",
searchPrice: {
min: null,
max: null
}
};
componentDidUpdate() {
const state = {
searchTitle: this.state.searchTitle,
searchPrice: this.state.searchPrice,
direction: this.state.direction
};
window.localStorage.setItem("saved_state", JSON.stringify(state));
}
componentDidMount() {
const state = JSON.parse(window.localStorage.getItem("saved_state"));
console.log(state);
if (state) {
this.setState({
searchTitle: state.searchTitle,
searchPrice: state.searchPrice,
direction: state.direction
});
}
}
// PRICE SORT
priceSort = key => {
this.setState({
data: shop.sort(
this.state.direction[key] === "asc"
? (a, b) => parseFloat(a.data[key]) - parseFloat(b.data[key])
: (a, b) => parseFloat(b.data[key]) - parseFloat(a.data[key])
),
direction: {
[key]: this.state.direction[key] === "asc" ? "desc" : "asc"
}
});
};
// OLD PRICE SORT
oldPriceSort = key => {
this.setState({
data: shop.sort(
this.state.direction[key] === "asc"
? (a, b) => parseFloat(a.data[key]) - parseFloat(b.data[key])
: (a, b) => parseFloat(b.data[key]) - parseFloat(a.data[key])
),
direction: {
[key]: this.state.direction[key] === "asc" ? "desc" : "asc"
}
});
};
// TITLE SORT
titleSort = key => {
this.setState({
data: shop.sort(
this.state.direction[key] === "asc"
? (a, b) => a.data[key].localeCompare(b.data[key])
: (a, b) => b.data[key].localeCompare(a.data[key])
),
direction: {
[key]: this.state.direction[key] === "asc" ? "desc" : "asc"
}
});
};
// TITLE FILTER
updateTitleSearch = event => {
this.setState({
searchTitle: event.target.value
});
this.titleSearch();
};
titleSearch = () => {
if (this.state.searchTitle) {
this.setState({
data: shop
.filter(item => {
return (
item.data.title
.toLowerCase()
.indexOf(this.state.searchTitle.toLowerCase()) !== -1
);
})
.sort(
this.state.direction.title === "asc"
? (a, b) => a.data.title.localeCompare(b.data.title)
: (a, b) => b.data.title.localeCompare(a.data.title)
)
});
}
};
// PRICE FILTER
updateMinSearchPrice = event => {
this.setState({
searchPrice: { ...this.state.searchPrice, min: event.target.value }
});
};
updateMaxSearchPrice = event => {
this.setState({
searchPrice: { ...this.state.searchPrice, max: event.target.value }
});
};
priceSearch = () => {
if (this.state.searchPrice.min || this.state.searchPrice.max) {
this.setState({
data: shop
.filter(item => {
return (
parseFloat(item.data.price) >= this.state.searchPrice.min &&
parseFloat(item.data.price) <= this.state.searchPrice.max
);
})
.sort(
this.state.direction.price === "asc"
? (a, b) => parseFloat(a.data.price) - parseFloat(b.data.price)
: (a, b) => parseFloat(b.data.price) - parseFloat(a.data.price)
)
});
}
if (!this.state.searchPrice.max) {
this.setState({
data: shop.filter(item => {
return parseFloat(item.data.price) >= this.state.searchPrice.min;
})
});
}
};
render() {
return (
<div className="page-container">
<h1>Welcome to ShopMeNow!</h1>
<Filters
updateTitleSearch={this.updateTitleSearch}
titleSearch={this.titleSearch}
updateMinSearchPrice={this.updateMinSearchPrice}
updateMaxSearchPrice={this.updateMaxSearchPrice}
priceSearch={this.priceSearch}
/>
<ItemTable
data={this.state.data}
priceSort={this.priceSort}
oldPriceSort={this.oldPriceSort}
titleSort={this.titleSort}
/>
</div>
);
}
}
export default App;
My aim is to fetch the saved data in the componentDidMount() hook. But it doesn't seem to work (i've already tried to console.log it)
What do I have to do in order to get it going? Thank you community!
instead of setting State in ComponentDidMount , why dont you create a entire different function and then call that function in ComponentDidMount.
All the Code of Setting State add in that function.
Try this and let me know if it works , Cheers !
ComponentDidMount(){
this.changeValues();
}
changeValues(){
const state = JSON.parse(window.localStorage.getItem("saved_state"));
console.log(state);
if (state) {
this.setState({
searchTitle: state.searchTitle,
searchPrice: state.searchPrice,
direction: state.direction
});
}
}
The issue I think is you are saving data in localStorage inside componentDidUpdate and you are trying to get the data from local storage in componentDidMount.
You need to understand that componentDidMount called before componentDidUpdate which means you are reading the data from local storage before you set.
So you need to first set the data and then read data
Is there a particular reason why you're doing it in componentDidUpdate? If not, I would suggest moving that functionality to a separate function. The way things stand now, any update, including this.setStates on data, which you don't want to save to localStorage.
Perhaps you might consider writing a function that sets state and saves to localStorage, seeing as how your sort functions are already quite bulky.
Sample pseudocode:
setStateWithLocalStorage = newState => {
const { searchTitle, searchPrice, direction } = this.state;
this.setState(newState, () => {
localStorage.setItem('saved_state', { searchTitle, searchPrice, direction })
})
}
then you can use this function instead of this.setState on your sort functions.
Consider the following code :
import React, { Component } from 'react';
class Counter extends Component {
state = { value: 5 };
increment = () => {
this.setState(prevState => ({
value: prevState.value + 1
}));
};
decrement = () => {
this.setState(prevState => ({
value: prevState.value - 1
}));
};
render() {
return (
<div>
{this.state.value}
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
</div>
)
}
}
How can I make it so that whenever I click the Decrement button, the value will not be less than 0. The value's minimum will always be zero and not -1, -2 ,-3 ,-4 ...
Just set a minimum value in your decrementing code:
decrement = () => {
this.setState(prevState => ({
value: Math.max(prevState.value - 1, 0)
}));
};
That's how number input works. To simplify the code you could try to use validity state (if your target browsers support it)
onChange(e) {
if (!e.target.validity.badInput) {
this.setState(Number(e.target.value))
}
}
Example
you can test it
const onPressDecrement = () => setCount((prevCount) => (Math.max(prevCount - 1,1)));
On Way Use Conditional (ternary) operator in decrement Function
decrement = () => {
this.setState(prevState => ({
value: prevState.value ? prevState.value -1 : 0
}));
};
I am trying to create a filter of a list.
The code I wrote is this:
constructor(props) {
super(props);
this.state = {
value: 'all',
textfield: ''
};
}
render() {
let filteredPlatform = fullList.filter((el) => {
return el.gameName.toLowerCase().indexOf(this.state.textfield) >= 0 && el.platform === this.state.value;
});
.....
<Table data={filteredPlatform} />
}
The platform value could be all, xbox, ps4 and so on.
I would like to show the entire not filtered list (by platform) at the start, because all is selected.
Any hint?
I'd generally break this out into a separate function and use an if statement to handle the "all" case, but here's another way to do it using the ternary operator:
const filteredPlatform = fullList.filter( el =>
el.gameName.toLowerCase().indexOf(this.state.textfield) >= 0 &&
(el.platform === this.state.value || "all" === this.state.value )
);
So if this.state.value is "all", then we return regardless of el.platform. Otherwise we return the filtered version.
Another, more expressive way, is to use 2 filters:
const filteredPlatform = fullList
.filter( el => el.gameName.toLowerCase().indexOf(this.state.textfield) >= 0 )
.filter( el => el.platform === this.state.value || "all" === this.state.value );
you can use ternary operator and check if state value is 'all' then assign fullList else assign filtered List
let filteredPlatform = this.state.value === 'all' ? fullList : fullList.filter((el) => {
el.gameName.toLowerCase().indexOf(this.state.textfield) >= 0 && el.platform === this.state.value;
});
If there is no selected platform (all), the list is not filtered.
let filteredPlatform = this.state.value === 'all'
? fullList : fullList.filter((el) => {
return el.gameName.toLowerCase().indexOf(this.state.textfield) >= 0 && el.platform === this.state.value;
});