Error when using if, when updating the state in react - javascript

I wanted to update this variable when the condition is true, but it doesn't let me, thanks
constructor(props){
super(props);
var isActive = false;
this.props.items.map(item => (
if(item.name == this.props.product.name) {
isActive = true;
}
));
this.state = {
active: isActive
};
console.log(isActive);
this.handleClick = this.handleClick.bind(this);
}

Reason is, you forgot to use {}, If you are using any condition or wants to do some calculation use {} and put all the statement inside that. One more thing since you just want to iterate the array means not returning anything, so i that case use forEach instead of map, Use this:
this.props.items.forEach(item => { //here
if(item.name == this.props.product.name) {
isActive = true;
}
});
Check this code it will produce the same error:
[1,2,3,4].forEach(el=>(
if(el % 2 == 0)
console.log(el);
))
Check the working example:
[1,2,3,4].forEach(el=>{
if(el % 2 == 0)
console.log(el);
})

You really aren't passing an 'active' property nor state. You are trying to set a computed property, much like Ember (see How to setup Ember like computed properties in Immutablejs and Redux and Flux and React). This was considered for React and dismissed.
You should just create a function, isActive() and call it when needed. I expect you only need it when rendering a set of individual item components for which isActive is a property.
That said, there are ways of cramming this into a React codebase, but your code will be unmaintainable.

Related

Change the object state value in ReactJs give me a warning ( Do not mutate state directly. Use setState()

How can you change the status as an object? I did it this way, but I don't think it's right, because in compiling it gives a setState warn.
I would like to understand how to change a state whose value is an object.
class Animation extends React.Component {
constructor(props) {
super(props);
this.state = {
step : step,
ledge :{zoom:1, display:"flex"},
map :{zoom:0, x:0, y:0, rotate:0},
};
}
StepForward = () => {
step = step + 1;
//STEP 1
if(step === 1){
this.setState({
...this.state.ledge.zoom = this.state.ledge.zoom - 1,
...this.state.ledge.display = "none"
});
}
}
StepBack = () => {
step = step - 1;
if(step < 0 ){
this.setState({step:step})
step = -1
}
//STEP 0
if(step === 0){
this.setState({
...this.state.ledge.zoom = this.state.ledge.zoom + 1,
...this.state.ledge.display = "flex",});
}
}
render() {
return (
<div id="content_animation">
<div id="step back" class="command" onClick={this.StepBack}>
<img class="arrow" src="img/arrow_b.svg" alt="back"/>
</div>
<div id="animation">
<AnimationStep
step = {this.state.step}
ledge={this.state.ledge}
map={this.state.map}/>
</div>
<div id="step forward" class="command" onClick={this.StepForward}>
<img class="arrow" src="img/arrow_f.svg" alt="forward"/>
</div>
</div>
)
}
}
export default Animation
when I compile it gives me the error that you see below but if you insert a comment above the line of code "wrong", then it works and compiles correctly ...
Compiled with warnings.
Do not mutate state directly. Use setState() react/no-direct-mutation-state
Do not mutate state directly. Use setState() react/no-direct-mutation-state
Do not mutate state directly. Use setState() react/no-direct-mutation-state
Do not mutate state directly. Use setState() react/no-direct-mutation-state
Search for the keywords to learn more about each warning.
To ignore, add //eslint-disable-next-line to the line before.
As the error clearly states, you're mutating your state directly, which will cause bugs along the way. You can set state without mutating it like this:
this.setState(state => ({
...state,
ledge: {
...state.ledge,
zoom: state.ledge.zoom - 1,
display: 'none'
}
}));
Useful links:
Mutating state - https://daveceddia.com/why-not-modify-react-state-directly/
Functional setState - https://www.freecodecamp.org/news/functional-setstate-is-the-future-of-react-374f30401b6b/
Object spreading - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Spread_in_object_literals
The problem is with your setState calls and how you're setting those values:
this.setState({
ledge: {
zoom: this.state.ledge.zoom - 1,
display: 'none'
}
});
Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable.
You perhaps would love to check difference between mutable and immutable aswell.
What you should do in this case you could use spread operator :
this.setState(prevState => ({
ledge: { // object that we want to update
...prevState.ledge, // keep all other key-value pairs
zoom: this.state.ledge.zoom -1 // update the value of specific key
}
}))
When you use this.setState, you don't have to explicitly say this.state in the assignments within it. I haven't been able to set the inner class the way you or the other answers have done. I usually do another step to successfully set the state.
this.setState({
...this.state.ledge.zoom = this.state.ledge.zoom + 1,
...this.state.ledge.display = "flex",});
becomes:
var tempLedge = this.state.ledge;
tempLedge.zoom = this.state.ledge.zoom + 1;
tempLedge.display = "flex";
this.setState({ledge = tempLedge});
Related, but not a dupe:
What is the correct way of setting state variables in Reactjs and what is the difference between these approaches?
Also, check out this link for more info: State and Lifecycle

Selected element within list in React

I want to apply different style for selected element from a long list.
I'm passing to React component element as props: currentId and selectedId.
Inside render function, I compare both ids and apply proper styles.
When clicking any element from the list, I fire an action with the new selected Id and all elements in the list will re-render(because selectedId prop does change).
If the list has 1000 element and I click one of them, It would be nice to only update 2 elements (new selected and deselected ones) not all of them.
Is these a better way to handle this scenario in React?
Update: Add code example
List component:
const MyList = (props) => {
const items = props.items;
const selectedId = props.selectedId;
return (
<div>
{items.map((item) => (
<MyItem
currentId={item.id}
selectedId={selectedId}
key={item.id}
content={props.content}
/>
))}
</div>
);
};
Item component:
const MyItem = (props) => {
const isSelected = props.currentId === props.selectedId;
return (
<div className={isSelected ? 'selected-item' : ''}>
<h1>{props.currentId}</h1>
</div>
);
};
You can implement shouldComponentUpdate logic to prevent components from rerendering. Generally this is a bad idea (more on that later) but it does seem to apply to your use case. In general it is better to simply use PureComponent to prevent unneeded rerenders. This implements shouldComponentUpdate logic that compares state and props and if neither has changed, no update occurs.
Without seeing your code this is my best guess as to what shouldComponentUpdate might look like in your context:
shouldComponentUpdate(nextProps) {
if(this.state.isSelected && this.state.id !== nextProps.selectedId) {
return true;
} else if (!this.state.isSelected && this.state.id === nextProps.selectedId) {
return true;
}
return false;
}
Note that this means that a rerender will not happen unless shouldComponentUpdate returns true or you call this.forceUpdate() on that component. Your component won't even render if this.setState() is called, unless you add in more specific logic so that shouldComponentUpdate returns true on state changes. This can lead to difficult to debug problems, where your UI fails to reflect changes in application state but no obvious error occurs. This behavior doesn't apply to child components, so if these components have children they will still rerender as expected. If you decide to implement shouldComponentUpdate, you can add logic to compare state as well by declaring the nextState parameter:
shouldComponentUpdate(nextProps, nextState) {
if(this.state.isSelected && this.state.id !== nextProps.selectedId) {
return true;
} else if (!this.state.isSelected && this.state.id === nextProps.selectedId) {
return true;
} else if (/*compare this.state to nextState */) { .... }
return false;
}
Implementing your own shouldComponentUpdate is tricky, and may require you to restructure your code for best results (for example, passing an isSelected variable to your components instead of allowing those components to decide whether or not they are selected might allow you to easily implement PureComponent). Best of luck!

Update state with setState ReactJs

I'm trying to update state variable when button click.but my issue is,it's update once with correct data then again it updated with constructor defined data.
constructor(props) {
super(props);
this.state = {
popupshow: [{ check: false, id: '' }]
}
}
componentDidUpdate(prevProps, prevState) {
console.log("this.state.popupshow",this.state.popupshow)
}
Details(type){
this.state.popupshow[i].id = type
this.state.popupshow[i].check = true;
this.setState({ popupshow: this.state.popupshow });
}
render() {
return (
<a onClick={() => this.Details("Tv Series")}>Update </>
)
}
my console.log is like bellow
You should not update React state directly. You should always update/set React state via setState method.
These lines are against React principal
this.state.popupshow[i].id = type
this.state.popupshow[i].check = true;
Update your Details as follows
Details(type){
let { popupshow } = this.state;
let i = 0;
popupshow[i].id = type
popupshow[i].check = true;
this.setState({ popupshow });
}
Note I dont have idea of variable i so assumed that as 0
I think you should rewrite details functions like :
Details(type, i){
const popupDetail = Object.assign([], this.state.popupshow);
popupDetail[i].id = type
popupDetail[i].check = true;
this.setState({ popupshow: popupDetail });
}
you are setting popupshow: this.state.popupshow this is causing forceupdate which re renders the component hence its value gets reset.
I totally agree with the other answers have given for the question, however there are few things worth noting is you might wanna add the function to the context.
The argument in favour of adding these lines to the constructor is so that the new bound functions are only created once per instance of the class. You could also use
onClick={this.Details.bind(this, "Tv Series")}
or (ES6):
onClick={() => this.Details("Tv Series")}
but either of these methods will create a new function every time the component is re-rendered.
Then change the function to arrow fucntion too like
Details(type, i){
const popupDetail = Object.assign([], this.state.popupshow);
popupDetail[i].id = type
popupDetail[i].check = true;
this.setState({ popupshow: popupDetail });
}

Is it good practice to add a condition in a state definition?

Relatively new to react. I've not seen this done often. Example:
this.state = {
varName: x.length != 0 ? 'Something' : null
}
Usually, you will define the initial state in the constructor with initial values, then on a component lifecycle, you could setState to that condition. Example
constructor(props) {
super(props);
this.state = {
varName:null
};
}
componentDidMount() {
// perhaps here evaluate your x value and then set the state
var x = something such as fetch or props passed
this.setState({
varName: x.length != 0 ? 'Something' : null
})
}
I don't see why that wouldn't work, but you'd have to be careful about where x is being defined. Usually I just leave all my state variables set to null or default values and then update them in componentWillMount, when I'll grab the information needed from props, localstorage, etc

Meeting multiple conditions that aren’t set simultaneously in componentWillReceiveProps

I need to use componentWillReceiveProps() to call a method in my component once three conditions are met. Two of these conditions compare current props to next props, and those two receive their values via an Ajax request. The problem is not all conditions will be true at the same time.
For example.
export class Styles extends Component {
componentWillReceiveProps(nextProps) {
if (
!_.isEmpty(nextProps.one) && // set via ajax request
!isEqual(this.props.two, nextProps.two) &&
!isEqual(this.props.three, nextProps.three) // set via ajax request
) {
this.myMethod();
}
}
myMethod() {
… do something
}
render() {
return (
<div />
)
}
}
Because two of the props are being set with an Ajax response, I can’t be sure when those values are set and when they’ll fulfill the condition. I obviously need to achieve three true values in order to call this.myMethod(), but instead I get various combinations of true/false at any given time. It’s a bit of a lottery scenario.
Do I ultimately need to manage each of these conditions temporarily in state, then clear them out when they’re met?
You could do this without the deprecated componentWillReceiveProps with something like this:
export class Styles extends Component {
isDirtyTwo = false;
isDirtyThree = false;
..
componentDidUpdate(prevProps) {
this.isDirtyTwo = this.isDirtyTwo || !isEqual(prevProps.two, this.props.two);
this.isDirtyThree = this.isDirtyThree || !isEqual(prevProps.three, this.props.three);
if (!_.isEmpty(this.props.one) && this.isDirtyTwo && this.isDirtyThree) {
this.isDirtyTwo = false;
this.isDirtyThree = false;
this.myMethod();
}
}
..
}
This will call myMethod when one is empty and both other props have changed at some point. (I'm assuming that once one is empty it stays that way, but if not, you could add another property for it.)

Categories