integer value not changing from function in React - javascript

image here Hi I am trying to get my click Power variable to double when function Upgrade is called however nothing is happening. Can anyone tell me why?

You need to make it this.clickPower *= 2 (in the Upgrade function), with the equals in order to alter the value of the variable.

You forgot to set an equal. The upgrade return is going nowhere, because upgrade is used as an onClick callback.
Using this.clickPower is not a good idea. If you want to initialize it in the render function, because it is not a props, state or ref.
React is rerendering following props and state, so you should set your clickPower in a state if you want to use it properly.
You should better initialize upgrade out of the render function.
// Not event callback mode :
let clickPower = 1;
function upgrade(value) => {
return value * 2;
}
clickPower = upgrade(clickPower);
// As callback but not in a React App
this.clickPower = 1;
function upgrade(e) => {
this.clickPower *= 2;
}
// Good way
constructor(props) {
super(props);
this.state = { clickPower: 1 };
}
function upgrade(e) => {
this.setState({ clickPower: this.state.clickPower * 2});
}
Plus :
const { money, setMoney } = this.props;

Related

How do i return an object from my react state

I am trying to find an item from a collection, from the code below, in order to update my react component, the propertState object isnt empty, it contains a list which i have console logged, however I seem to get an underfined object when i console log the value returned from my findProperty function... I am trying update my localState with that value so that my component can render the right data.
const PropertyComponent = () => {
const { propertyId } = useParams();
const propertyState: IPropertiesState = useSelector(
propertiesStateSelector
);
const[property, setProperty] = useState()
const findProperty = (propertyId, properties) => {
let propertyReturn;
for (var i=0; i < properties.length; i++) {
if (properties[i].propertyId === propertyId) {
propertyToReturn = properties[i];
break;
}
}
setProperty(propertyReturn)
return propertyReturn;
}
const foundProperty = findProperty(propertyId, propertyState.properties);
return (<>{property.propertyName}</>)
}
export default PropertyComponent
There are a few things that you shall consider when you are finding data and updating states based on external sources of data --useParams--
I will try to explain the solution by dividing your code in small pieces
const PropertyComponent = () => {
const { propertyId } = useParams();
Piece A: Consider that useParams is a hook connected to the router, that means that you component might be reactive and will change every time that a param changes in the URL. Your param might be undefined or an string depending if the param is present in your URL
const propertyState: IPropertiesState = useSelector(
propertiesStateSelector
);
Piece B: useSelector is other property that will make your component reactive to changes related to that selector. Your selector might return undefined or something based on your selection logic.
const[property, setProperty] = useState()
Piece C: Your state that starts as undefined in the first render.
So far we have just discovered 3 pieces of code that might start as undefined or not.
const findProperty = (propertyId, properties) => {
let propertyReturn;
for (var i=0; i < properties.length; i++) {
if (properties[i].propertyId === propertyId) {
propertyToReturn = properties[i];
break;
}
}
setProperty(propertyReturn)
return propertyReturn;
}
const foundProperty = findProperty(propertyId, propertyState.properties);
Piece D: Here is where more problems start appearing, you are telling your code that in every render a function findProperty will be created and inside of it you are calling the setter of your state --setProperty--, generating an internal dependency.
I would suggest to think about the actions that you want to do in simple steps and then you can understand where each piece of code belongs to where.
Let's subdivide this last piece of code --Piece D-- but in steps, you want to:
Find something.
The find should happen if you have an array where to find and a property.
With the result I want to notify my component that something was found.
Step 1 and 2 can happen in a function defined outside of your component:
const findProperty = (propertyId, properties) => properties.find((property) => property.propertyId === propertyId)
NOTE: I took the liberty of modify your code by simplifying a little
bit your find function.
Now we need to do the most important step, make your component react at the right time
const findProperty = (propertyId, properties) => properties.find((property) => property.propertyId === propertyId)
const PropertyComponent = () => {
const { propertyId } = useParams();
const propertyState: IPropertiesState = useSelector(
propertiesStateSelector
);
const[property, setProperty] = useState({ propertyName: '' }); // I suggest to add default values to have more predictable returns in your component
/**
* Here is where the magic begins and we try to mix all of our values in a consistent way (thinking on the previous pieces and the potential "undefined" values) We need to tell react "do something when the data is ready", for that reason we will use an effect
*/
useEffect(() => {
// This effect will run every time that the dependencies --second argument-- changes, then you react afterwards.
if(propertyId, propertyState.properties) {
const propertyFound = findProperty(propertyId, propertyState.properties);
if(propertyFound){ // Only if we have a result we will update our state.
setProperty(propertyFound);
}
}
}, [propertyId, propertyState.properties])
return (<>{property.propertyName}</>)
}
export default PropertyComponent
I think that in this way your intention might be more direct, but for sure there are other ways to do this. Depending of your intentions your code should be different, for instance I have a question:
What is it the purpose of this component? If its just for getting the property you could do a derived state, a little bit more complex selector. E.G.
function propertySelectorById(id) {
return function(store) {
const allProperties = propertiesStateSelector(store);
const foundProperty = findProperty(id, allProperties);
if( foundProperty ) {
return foundProperty;
} else {
return null; // Or empty object, up to you
}
}
}
Then you can use it in any component that uses the useParam, or just create a simple hook. E.G.
function usePropertySelectorHook() {
const { propertyId } = useParams();
const property = useSelector(propertySelectorById(propertyId));
return property;
}
And afterwards you can use this in any component
functon AnyComponent() {
const property = usePropertySelectorHook();
return <div> Magic {property}</div>
}
NOTE: I didn't test all the code, I wrote it directly in the comment but I think that should work.
Like this I think that there are even more ways to solve this, but its enough for now, hope that this helped you.
do you try this:
const found = propertyState.properties.find(element => element.propertyId === propertyId);
setProperty(found);
instead of all function findProperty

React Function Component use variable (not state)

With React Class Component, I use some variable (not this.state) helping my control logic. Example: this.isPressBackspace = false and when I set variable don't make component re-render (ex: this.isPressBackspace = true).
That's working perfect in Class Component but when I change to Function Component, I dont know where to place this.isPressBackspace.
Here is my example in codesandbox.
https://codesandbox.io/s/function-component-example-3h98d
useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.
const isPressBackspaceRef = React.useRef(false);
const keyDownPositionRef = React.useRef({});
const onKeyDown = (e) => {
// this is wrong syntax
// this.keyDownPosition OR let keyDownPosition
keyDownPositionRef.current = {
start: e.target.selectionStart,
end: e.target.selectionEnd
};
switch (e.key) {
case "Backspace":
isPressBackspaceRef.current = true; // this is wrong syntax ????
break;
default:
break;
}
};
const onChange = (e) => {
const { end } = keyDownPositionRef;
if (isPressBackspaceRef.current) {
const length = end - e.target.selectionEnd;
alert(`You delete ${length} character`);
}
isPressBackspaceRef.current = false;
};
In my experience you don't use the this keyword when working with function components. Instead you use hooks like useState.
Check the following video for getting started with hooks:
https://www.youtube.com/watch?v=O6P86uwfdR0&ab_channel=WebDevSimplified

How to get the updated value of a state from a callback method?

I am building a React app and I have a code following this logic:
class ComponentTest extends Component {
state = {test: 0}
testingHandler = () => {
console.log(this.state.test)
}
updateHandler = () => {
let test = Math.random()
this.setState({test})
this.testing()
}
render () {
return (
<button onClick={this.updateHandler}>Update</button>
)
}
}
What I need to do is get the updated value of test in testingHandler(), however it doesn't happen, testingHandler just get the past value, it is like the state that is being received by testingHandler is always one step late.
For example, let's say that test = 0, then I click on the button that calls updateHandler() and now test = 1, after that updateHandler() calls testingHandler(), which I expect to get the new value of test which now is 1, however I get the old value 0. If I call updateHandler() again and update test to 2 I'll get 1 in testingHandler(), which is the past value.
How can I get this value updated from testingHandler?
I did everything that I could imagine, but I couldn't get this done. I believe it has something to do with the render logic of React, but I don't know exactly how this is working.
P.S. Passing the value as an argument is not an option.
setState is asynchronous.
React may batch multiple setState() calls into a single update for performance.
Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.
You can pass a callback function as the second argument of setState that will run right after the state has updated. So in you case, you could do this:
updateHandler = () => {
let test = Math.random()
this.setState( {test}, this.testingHandler )
}
copied from react documentation link: https://reactjs.org/docs/faq-state.html
Calls to setState are asynchronous - don’t rely on this.state to reflect the new value immediately after calling setState. Pass an updater function instead of an object if you need to compute values based on the current state
better you can pass it as a callback function or you can also pass the value to the function.
This link is also helpful: setState doesn't update the state immediately
class ComponentTest extends Component {
state = { test: 0 };
testingHandler = () => {
console.log(this.state.test);
};
updateHandler = () => {
let test = Math.random();
this.setState({ test }, () => this.testingHandler()); // pass it as a callback
};
render() {
return <button onClick={this.updateHandler}>Update</button>;
}
}

ReactJS/Redux - Pure vs Impure Javascript functions?

I have gone through the definitions of the Pure and Impure Javascript functions in the ReactJs Official Docs.
Pure functions are ones that do not attempt to change their inputs, and always return the same result for the same inputs.
Example
function sum(a, b) {
return a + b;
}
Impure function is one that changes its own input.
Example
function withdraw(account, amount) {
account.total -= amount;
}
Now, can somebody tell me, how can I mistakenly make functions impure in React/Redux, where pure functions are required?
React and Redux both need pure functions coupled with immutability to run in a predictable fashion.
If you don't follow these two things, your app will have bugs, the most common being React/Redux not able to track changes and unable to re-render when your state/prop changes.
In terms of React, consider the following example:
let state = {
add: 0,
}
function render() {
//...
}
//pure function
function effects(state,action) {
//following immutability while updating state, not directly mutating the state.
if(action == 'addTen') {
return {...state, add: state.add + 10}
}
return state;
}
function shouldUpdate(s) {
if(s === state){
return false
}
return true
}
state = effects(state, 'addTen')if(shouldUpdate(state)) {
render();
}
The state is held by the state object which has only added property. This app renders the app property. It shouldn't always render the state when anything happens but should check whether a change occurred in the state object.
Like so, we have an effects function, a pure function which we use to affect our state. You see that it returns a new state when the state is to be changed and returns the same state when no modification is required.
We also have a shouldUpdate function which checks using the === operator whether the old state and the new state is the same.
To make mistakes in terms of React, you can actually do the following :
function effects(state,action) {
doRandom(); // effects should only be called for updating state.
// Doing any other stuff here would make effects impure.
if(action == 'addTen') {
return {...state, add: state.add + 10}
}
return state;
}
You can also make mistakes by setting the state directly and not using effects function.
function doMistake(newValue) {
this.state = newValue
}
The above should not be done and only effects function should be used to update the state.
In terms of React, we call effects as setState.
For Redux:
Redux's combineReducers utility checks for reference changes.
React-Redux's connect method generates components that check reference changes for both the root state and the return values from mapState functions to see if the wrapped component actually needs to re-render.
Time-travel debugging requires that reducer be pure functions with no side effects so that you can correctly jump between different states.
You can easily violate the above three by using impure functions as reducers.
Following is taken directly from redux docs:
It's called a reducer because it's the type of function you would pass to Array.prototype.reduce(reducer, ?initialValue).
It's very important that the reducer stays pure. Things you should never do inside a reducer:
Mutate its arguments;
Perform side effects like API calls and routing transitions;
Call non-pure functions, e.g. Date.now() or Math.random().
Given the same arguments, it should calculate the next state and return it. No surprises. No side effects. No API calls. No mutations. Just a calculation.
Simply said the state cannot be mutated. A new instance of the state should be returned every time there is a change so
This code is not correct :
const initialStates = {
items: ['item1']
}
export const ItemMaster = (state = initialStates, action) => {
switch (action.type) {
case TYPES.ADD_ITEM:
{
state.items.push(action.item)
return state
}
default:
return state
}
}
This code when written as a pure function below, This returns a new instance of the array it does not modify the actual array itself. This is the reason you should use a library like immer to handle immutability
const initialStates = {
items: ['item1']
}
export const ItemMaster = (state = initialStates, action) => {
switch (action.type) {
case TYPES.ADD_ITEM:
{
state = {...state,items:state.items.concat(action.item)}
return state
}
default:
return state
}
}
You could make pure functions impure by adding API calls or writing codes that result in side effects.
Pure functions should always be on point and self-explanatory, and should not require you to refer 3 or 4 other functions to understand what's going on.
// Pure Function
function USDtoEUR(USD, todayRate) {
return USD * todayRate;
}
// Impure Function
function USDtoEUR(USD) {
const todayRate = getTodayRate();
return USD * todayRate;
}
In case of React / Redux
const mapState = async state => {
const { data } = await whatDoINeed()
let mappedState = {}
if (data.needDolphin) {
mappedState.dolphin = state.dolphin
}
if (data.needShark) {
mappedState.shark= state.shark
}
return mappedState;
}
// Or for Redux Reducer
// Bad
{
setData: (state, payload) => {
const set = whatToSet()
return {
...state,
set.dolphin ? ...{ dolphin: payload.dolphin } : ...{},
set.shark ? ...{ shark : payload.shark } : ...{},
}
}
}
// Good
{
setData: (state, payload) => {
return {
...state,
// Just send only the things need
// to be sent
...payload
}
}
}
This should not be done. Everything a connect function or reducer function needs must be supplied through argument or written within its function. It should never get from outside.

React, setState in componentDidMount doesn't always change the state value

I'm relatively new to React and I'm trying to change the value of one of my state properties at random once the page has rendered. But using setState in componentDidMount doesn't seem to work every time, sometimes I get the original state value returned (Which should never happen)
Is there something I'm doing wrong here;
constructor(props) {
super(props);
this.state = {
houseAd: null
};
}
and then to setState
componentDidMount() {
const houseAds = ['ad1', 'ad2'];
const rand = houseAds[Math.floor(Math.random() * houseAds.length)];
this.setState({
houseAd: rand
});
}
Sometimes I get one or the other from my houseAds array, but sometimes it just returns null
Then in my render I'm just doing something simple like;
let ad;
if (this.state.houseAd === 'ad1') {
ad = 'Ad1';
}
if (this.state.houseAd === 'ad2') {
ad = 'Ad2'
}
But obviously when the state value is null, nothing shows up
Code seems to be fine, only 1st time you will get null next time you will not get null values, check the state value using call back function after updating like this.
this.setState({
houseAd: rand
}, ()=> {console.log(this.state.houseAd});
componentDidMount is called after initial render - you probably didn't notice that - second render call is forced by setState quickly fixes/hides initial state.
console.log(this.state.houseAd) in render to proove that.
If you need sth at start - do it in constructor.

Categories