My State value is not Changing ,when button is pressed - react-native

onButtonPress = () => {
min = 1000;
max = 9999;
randomotp = min + (Math.random() * (max - min));
console.log(Math.round(randomotp));
this.setState({
otpfield:'#48A23A'
});
console.log('result',this.state.otpfield);
}
}
I have been executing this function in the Button on click , but the corresponding (i,e Otpfield) value is not changing

React does not update the state immediately, it's an asynchronous operation. Therefore your console.log() call is invoked too fast and the state is not yet changed.
Use the "afterUpdated" callback instead (second parameter of the setState method):
this.setState(
{property: true},
() => console.log(this.state.property)
);

The state will not change. onButtonPress function must finish executing first before changing the state.
use componentDidUpdate lifecycle method to check if the state changed
componentDidUpdate(prevProps, prevState) {
console.log('result',this.state.otpfield);
//new State
console.log('result',prevState.otpfield);
// prev State
}

Related

Is there a cleaner way to organize this recoilJS state?

I've just learned about recoilJS and have been playing around with it a bit and have a question about whether what I've done is considered "correct." My code works, but it feels weird.
I've got the following React function component:
export const TimerPanel: FC = () => {
const gameState = useRecoilValue<GameState>(HeaderAtoms.gameState);
const timerCount = useRecoilValue(HeaderAtoms.timerCount);
const setTimerCounter = useSetRecoilState(HeaderAtoms.timerCounter);
useEffect(() => {
if (gameState === GameState.IN_PROGRESS && timerCount < 1000) {
window.setTimeout(() => {
setTimerCounter(timerCount + 1);
}, 1000);
}
});
return <NumberPanel num={timerCount} />;
};
where the relevant atom and selector are defined as:
export const timerCount = atom<number>({
key: 'Header.timerCount',
default: 0
});
export const timerCounter = selector<number>({
key: 'Header.timerCounter',
get: ({ get }) => {
return get(timerCount);
},
set: ({ get, set }, newCount) => {
if (get(gameState) === GameState.NEW) {
set(timerCount, 0);
} else if (get(gameState) === GameState.IN_PROGRESS) {
set(timerCount, newCount);
}
}
});
Basically, when the game starts, the TimerPanel increments the timer display by 1 every second the game is in progress. If the user resets the game (GameState.NEW), timerCount resets back to zero. If the atom/selector aren't done properly, there's a race condition in that the game state and timer count will reset, but the timer is still going and will still update the TimerPanel one more time. This is why I have the if blocks in my selector's set prop.
Basically, I'm concerned that my timerCounter selector is a glorified filter/pass-thru entity for the timerCount state and am wondering if there's a better way to handle this use case.
If your concern is the race condition, in your code, I don't see how your timer would click. setTimeout will tick once.
Anyway, you have 2 states, game state and timer state. You want to reset timer when game state changes. How about doing it in a game state selector? or move the logic into a custom hook and operate on these 2 states directly.

Vuex can't stop setInteval

I have a method in Vuex:
export const startTime = ({ commit, state }, status) => {
let timeInterval
if(status) {
const timer = 1000
timeInterval = setInterval(() => {
console.log('x')
commit('SET_RUNNED_TIME', parseInt(state.runnedTime += timer))
}, timer)
}
else {
console.log('y')
clearInterval(timeInterval)
commit('SET_RUNNED_TIME', 0)
}
}
From my component I send value true or false to method startTime(). When I send true then method run commit SET_RUNNED_TIME. But when I send false clearInterval(timeInterval) not stopping setInterval and still is sending commit('SET_RUNNED_TIME' ...)
The variable timeInterval is inside the scope of the function. If you want it to keep on living between different calls to startTime you need to put it outside the function scope. For example in the state.

update variable inside componentDidUpdate fails

I'm having a popup in my view and inside the popup there's a countdown timer. I need to hide the popup when countdown timer has value1 . This is what I tried.
componentDidUpdate() {
if (this.state.count === 1) {
clearInterval(this.intervalDuration);
this.setState({popupvisible:false})
}
}
I'm getting an error when the count equals to 1 as follows.
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
You have to add condition in componentDidUpdate,
The componentDidUpdate is particularly useful when an operation needs to happen after the DOM is updated
componentDidUpdate(prevProps) {
if (prevProps.data !== this.props.data) {
if (this.state.count === 1) {
clearInterval(this.intervalDuration);
this.setState({popupvisible:false})
}
}
}
You can learn more about componentDidUpdate on official document :
https://reactjs.org/docs/react-component.html#componentdidupdate
If you are setting a state variable, then that variable can also be added in condition to avoid recurring update.
componentDidUpdate() {
if (this.state.count === 1) {
clearInterval(this.intervalDuration);
if(this.state.popupvisible){
this.setState({popupvisible:false})}
}
}
This is happening because when count reaches the value 1 yourcomponentDidUpdate sets the state and since there is no check to control when to update your state based on popupVisible's value, your componentDidUpdate is called again and again causing an infinite loop. What you'd what to do is have a check if popupVisible is true, then only set it to false.
componentDidUpdate() {
if (this.state.count === 1) {
clearInterval(this.intervalDuration);
if(this.state.popupvisible) {
this.setState({ popupvisible:false });
}
}
}

How to toggle a boolean value using Context and Hooks?

I am using ReactContext and Hooks to show and hide a Modal on click of a button.
Following is my Context code
const setPrivacyPolicyModalVisibility = dispatch => {
return ({visible}) => {
visible
? dispatch({type: 'enablePrivacyPolicyModalVisibility'})
: dispatch({type: 'disablePrivacyPolicyModalVisibility'});
};
};
And the reducer code for the same is something as follows
case 'enablePrivacyPolicyModalVisibility':
return {...state, ...{enablePrivacyPolicy: true}};
case 'disablePrivacyPolicyModalVisibility':
return {...state, ...{enablePrivacyPolicy: false}};
Some setup code in my class
const {state, setPrivacyPolicyModalVisibility} = useContext(Context);
const [privacyVisibility, setPrivacyVisibility] = useState(false);
on click of button I am calling the following code
<TouchableOpacity
onPress={() => {
setPrivacyVisibility(true);
console.log(`${privacyVisibility}`);
setPrivacyPolicyModalVisibility({privacyVisibility});
}}.....
As you can see I am console logging the privacyVisibility value but it is always false which I fail to understand
Following is my code in the component to hide or show the Modal
{state.enablePrivacyPolicy ? (
<SettingsPrivacyModal visible={true} />
) : (
<SettingsPrivacyModal visible={false} />
)}
The Modal code is proper as I have tried setting default value to true just to check if modal is visible then it works, but on click of button press the state value does not change and I am not able to see the modal as the value is always false
The issue seems to be in the onPress callback:
onPress={() => {
const privacyVisibility_new = !privacyVisibility;
console.log( privacyVisibility_new );
setPrivacyVisibility( privacyVisibility_new );
setPrivacyPolicyModalVisibility( privacyVisibility:privacyVisibility_new );
}}
When the cycle reaches the callback privacyVisibility has the default which is false. I think you are assuming that once setPrivacyVisibility is called, the privacyVisibility variable will have the new value in that same cycle; but it won't have the updated value until the component renders again.
setPrivacyPolicyModalVisibility doesn't seem to be correct. I am not sure where is dispatch exactly, but assuming it is at the same level as the function you can simply use it inside.
const setPrivacyPolicyModalVisibility = visible => {
if ( visible ) {
dispatch({ type: "enablePrivacyPolicyModalVisibility" });
} else {
dispatch({ type: "disablePrivacyPolicyModalVisibility" });
}
};
You might want to simplify your reducer and send directly the visible value:
const setPrivacyPolicyModalVisibility = visible =>
dispatch({ type: "setPrivacyPolicyModalVisibility", payload: visible });
.
case 'setPrivacyPolicyModalVisibility':
return { ...state, is_privacyPolicy_visible: action.payload };
Actually the error was simple. I am using the visible parameter as props in setPrivacyPolicyModalVisibility but while setting I am passing prop of different name
Thanks to #Alvaro for pointing me in the right direction

React native state not updating

I feel like Im going crazy here.....
I type in "x" to the searchbar but this.setState({ filter: text }); is not updating state.... console.log(this.state.filter); gives me a value of '' (its initial value set in constructor).
I can see the value of text variable is x...but its just not updating the filter state.
constructor(props) {
super(props);
this.state = {
timer: 30 * 60,
lat: 0,
lng: 0,
loading: false,
data: [],
pagetoken: null,
refreshing: false,
waiting4answer: false,
placeName: null,
placeUri: null,
filter: '',
};
}
renderHeader = () => {
if (this.state.waiting4answer === false) return null;
return (
<SearchBar
placeholder="Type Here..."
lightTheme
round
onChangeText={(text) => {
this.setState({ filter: text });
console.log(this.state.filter);
this.searchFilterFunction();
}}
autoCorrect={false}
/>
);
};
The state is updating, it's just the way that you are checking and using the updated state is flawed.
State is Asynchronous
State is asynchronous, it takes time for the state to set. The problem you are encountering is that you are calling setState and then immediately logging the value from state. Unfortunately when you do this the state will not have updated by this time you log it, so you are getting the previous value.
State takes a callback
If you want to use the value of state that you have just set then you need to use the callback function that setState has. this.setState({key: value}, callback)
This callback allows you to run functions after the state has been set. You can use it in the following way:
this.setState({filter: text}, () => {
// put the things you wish to occur after you have set your state.
console.log(this.state.filter);
// I am guessing your searchFilterFunction requires the updated filter value in state
// so put that here too
this.searchFilterFunction();
});
This means that once you set the value of filter in the state and the state has updated to reflect that value it will then run the callback, so it will log the value of filter that is now in state, and then it will run the searchFilterFunction.
Further reading
You can read more about state in this series of great articles by Michael Chan
https://medium.learnreact.com/setstate-is-asynchronous-52ead919a3f0
https://medium.learnreact.com/setstate-takes-a-callback-1f71ad5d2296
https://medium.learnreact.com/setstate-takes-a-function-56eb940f84b6
use the setState callback to get the updated state immediately after setting it
this.setState({ filter: text }, () => {
console.log(this.state.filter);
});
react setState is asynchronous