React: Dynamically created state variable - javascript

I tried to run the code below, but I got an undefined from the console.log statement. Any thoughts?
this.setState({ [show]: true })
console.log("this.state.show: " , this.state.show);

In your code you don't set state exactly for show.
Example:
const show = 'light';
this.setState({[show]: false}) // you set state for 'light'(this.state.light: false)
If you don't set variable show before, you should use:
this.setState({ show: true })
And if you need to get state right after setting:
this.setState({ show: true }, () => console.log("this.state.show: " , this.state.show);)

If you are trying to check if state did update the best way to do that is simply to check for it inside the render() function, because the component is always re-rendered when you update the state. This would probably look like this (I have added a ternary operation as an example of how you can show and hide your component):
render(){
console.log(this.state.show);
return this.state.show ? <MyComponent /> : null;
}
But if you really want to check if the state changed just after using the setState function, for example inside another function (and not render()), you will need to call console.log inside a callback. This is because state takes some time to update and therefore synchronous code would fail. setState takes callback functions as a second parameter. So, you can just re-write like this:
this.setState({ show: true }, () => console.log("this.state.show: " , this.state.show));
Hope that helped...

Related

need to pass an effect via props or force component reload from outside the root component in preact/react

I have a situation that an item outside the component might influence the item in the backend. ex: change the value of one of the properties that are persisted, let's say the item status moves from Pending to Completed.
I know when it happens but since it is outside of a component I need to tell to the component that it is out of sync and re-fetch the data. But from outside. I know you can pass props calling the render method again. But the problem is I have a reducer and the state will pick up the last state and if I use an prop to trigger an effect I get into a loop.
Here is what I did:
useEffect(() => {
if (props.effect && !state.effect) { //this runs when the prop changes
return dispatch({ type: props.effect, });
}
if (state.effect) { // but then I get here and then back up and so on
return ModelEffect[state.effect](state?.data?.item)}, [state.status, state.effect, props.effect,]);
In short since I can't get rid of the prop the I get the first one then the second and so on in an infinite loop.
I render the root component passing the id:
render(html`<${Panel} id=${id}/>`,
document.getElementById('Panel'));
Then the idea was that I could do this to sync it:
render(html`<${Panel} id=${id} effect="RELOAD"/>`,
document.getElementById('Panel'));
any better ways to solve this?
Thanks a lot
I resolved it by passing the initialized dispatch function to a global.
function Panel (props) {
//...
const [state, dispatch,] = useReducer(RequestReducer, initialData);
//...
useEffect(() => {
//...
window.GlobalDispatch = dispatch;
//...
}, [state.status, state.effect,]);
with that I can do:
window.GlobalDispatch({type:'RELOAD'});

How to use updated state value above render function?

I think it might be silly question to ask but trust me I am stuck to find an answer . Actually , I am trying to access updated state value in class function above render function but I am not getting updated value . when I console value in render function I got updated value . Could someone please help me how to access updated value .
Thanks
Code
fetchAgents = e => {
this.setState({
value: e.target.value
});
};
fetchFilteredInventories = e => {
axios
.get(`/api/reports/agents/?branch=${this.state.value}`)
.then(response => {
this.setState({
agents: response.data
});
});
};
when I try to access updated state value in fetchFilteredInventories I am getting null value . Could someone help me to achieve my goal
setState is asynchronous. When you console.log after setState, the state is not changed yet, it is in the process of changing. Try this
this.setState({
value : e.target.value
},()=>console.log(value));
You will see the value is updated. setState allows a callback function as arguement. So use the callback function to use the updated state value.
Read the docs for further info: https://reactjs.org/docs/state-and-lifecycle.html#using-state-correctly
It depends on where you are calling your fetchFilteredInventories function.
After a state update in a React component certain lifecycle hooks get called, such as componentWillUpdate, componentDidUpdate. you can read about them in React docs here State and Lifecycle.Make sure you are calling your API call function at the right moment.If you can, put your whole component code here for better answers.
Try This
axios.get(`/api/reports/agents/?branch=${this.state.value}`).then(function(response) {
this.setState({
agents: response.data
});
}.bind(this));

Cant change variable with callback function but console logging works

I am trying to change a variable in react with a callback function but cannot seem to do so. Here is my react component:
const MyComponent = () => {
let scenePinned;
const sceneCallback = event => {
if (event && event.state === 'DURING') {
console.log('Pinned');
scenePinned = true;
} else {
console.log('Not Pinned');
scenePinned = false;
}
};
console.log(scenePinned);
return (
<div>
<div style={scenePinned ? 'pinned' : 'not pinned'}/>
{(progress, event) => (
//Stuff Happens Here
), sceneCallback(event) )}
</div>
);
}
I am using react-scrollmagic and am trying to get the scenePinned variable to change from false to true and back to false again when scene is pinned to top. The console logging of Pinned and Not Pinned is happening correctly but I cannot seem to change the scenePinned variable. I am sure this is something very basic that I am not getting but I cannot understand why this is happening. Any help would be appreciated.
Note: I have tried using state to store the value but the callback is fired on scroll so the maximum depth is exceeded when trying to use state to store the scrolling status.
You need to use state for this. Otherwise the variable is reinitialized every time the component is rendered, and the value is lost.
console.log(scenePinned);
will run for the first time when the page loads
with react we use state the handle dynamic values.
or use rxjs
or create your own object and set listeners on it. with some custom event
so ex. with state
state={scenePinned:null}
then inside render method console.log(this.state.scenePinned)
A possible solution is to define a state variable in a parent component that will pass it to <MyComponent> as a prop.
Them move the sceneCallback function to the parent component and pass it as a prop to <MyComponent>
An explanation on how to define such a callback exists in many places. Here is one: (mine... ;) https://stackoverflow.com/a/55555578/5532513

I need clarification for State and Lifecycle of react

I'm currently learning React and I don't fully understand why this is wrong:
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});
And this is correct:
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
Could someone give me a real world example where i can use this "second form of setState()" that accepts a function?
This is the link
Say you have a CheckBoxComponent, whose state you initialize like this in the constructor:
this.state = {enabled: true}
You want to update its state when a user clicks on the checkbox. So you write this click handler:
function toggleCheckbox() {
this.setState({enabled: ???});
}
This kind of situation is what the second type of setState is for. The click handler should be written as:
function toggleCheckbox() {
this.setState(prevState => ({enabled: !prevState.enabled}));
}
Because this.props and this.state may be updated asynchronously, you
should not rely on their values for calculating the next state.
1) You can just use this snippet in most situations as long as you didn't use the current state/props to calculate for the next state.
For example, this snippet only goes to fetch data from github and update to its state. We can just put an object inside this.setState().
class FetchGithub extends react.Component{
state = {
//...
};
componentDidMount() {
fetch('https://api.github.com/repos/facebook/react/commits')
.then(data => this.setState(data.json()))
.catch(err => this.setState(err));
}
}
2) But once the scenario is to use the current state/props to calculate for the next state, then you need to put instead a function to make sure that our current state gets updated already.
this.setState((state, props) => ({
counter: state.counter + props.increment
}));
[Updated]
Since props is the argument that is been passed from this component's parent or redux's reducers, which means it takes time to process. So you also need to make sure the props is the most updated one.
Let's look at your code example again. There should be 2 components:
Parent component, that control either +1 or -1 -> AdjustComponent
Child component, just for display the result -> DisplayComponent
So the proper flow is the user click on +1/-1, AdjustComponent passes the props into DisplayComponent. And then DisplayComponent get to update its state by its current state and props sent by AdjustComponent. And show to the screen.
But what if the user click on -1 and then +1 very very very quickly or if user's computer suddenly has huge loading to deal with that affect their browser performance. So that when you use this snippet:
this.setState({
counter: state.counter + props.increment
});
The newest props(which should be +1) hasn't been received from AdjustComponent yet, but DisplayComponent updated already, using the old props.increment, which is -1 that leads to the wrong result.

how to clear the react state array?

How to clear the existing data in react state variable (Array) and assign another array to it. I have try below thing but it doesn't works.
itemsChanged(items) {
this.setState({item : []}) //item is my state variable
this.setState({item : items})
console.log("ITEMS : ",this.state.item) //this will not print the updated value
}
Thanks in advance
You don't need to assign an empty array first. Just pass the new array to it. The only reason why it's not working is that setState is an asynchronous call. Use it like this
this.setState({item : items}, () => console.log("ITEMS : ",this.state.item) )
According to React's docs
React may batch multiple setState() calls into a single update for performance.
If you want to check your state value after setState, you should do like:
this.setState({item : items}, () => console.log(this.state.item));
setState is an async method. So, when you print it on console, It still can be updating. You can use console log before return render.
...
render(){
console.log("ITEMS : ",this.state.item);
return (<div>...</div>)
}
...
As they describe:
setState(updater, [callback])
so that may suggest it is not a synchronous operation.
Use:
itemsChanged(items) {
var me = this;
me.setState({item : items}, function(){
console.log("ITEMS : ", me.state.item);
});
}
One thing you should understand about setState is that it works asynchronously. If you try to console.log the state directly after calling setState, you won't see any changes yet.
You also don't have to clear out the array by calling setState with an empty array--you can just replace the current array with the new array.
this.setState({ items: newItems });
If you want to log the change, I'd suggest trying to do it in the component's componentShouldUpdate method.
setState is an async function,if you are writting the code as that:
this.setState({xxState})
console.log(this.state.xxState)
The program will execute the console.log first,so you should write as that:
this.setState({xxx},()=> {
console.log(this.state.....)
})
And it will be work well.

Categories