I am trying to update the value of a state from another function.
I have declared them like so:
const App () => {
const [positionAX, setPositionAX] = useState(100)
const [positionAY, setPositionAY] = useState(100)
}
outside of App
I have another function:
const setPosition = () => {
setPositionAX(200);
setPositionAY(200);
}
When I call setPosition()
I get the error:
Cant find Variable: setPositionAX
Cant find Variable: setPositionAY
I tried to move const [positionAX, setPositionAX] = useState(100)
to the top of my file but then I got the error:
Invalid hook call. Hooks can only be called inside of the body of a function.
How do I update that variable from other functions?
I can't seem to get this to work, I am not sure what I am doing wrong
Here is a live snack example of the code you gave me: https://snack.expo.io/Cd!hwDQ0m
If I add an alert:
alert("pressed")
Into the handleClick function, that works so for some reason it is just not working with the setPositionA([200, 200])
.
Also as an additional note: In my app example, there are two functions and the functionality of setting the state, and the functionality of displaying the state are separated which is why I am getting the issue I meant to present in my initial Stack overflow post.
Here is a snack of that example of what I am trying to achieve:
https://snack.expo.io/6TUAkpCZM
I am using the 'positionX' and 'positionY' as vars to define the Top and Left position of an element which are rendered out, however, the actual setting of the positionX
and positionY
variable is done in another function
I am a junior developer so I really want to thank you for all your help with this and also apologise if this is super nooby.
I tried your way and I just can't seem to get it to work. I think there is some confusion as to what I want to achieve and where I want to achieve it. That is probably my fault as I am a noobie developer so please forgive me. I didn't want to just post all my code as I think its frowned upon for people to just code dump and be like "fix this" - however, for this situation its probably best haha.
Here is a full snack of my code: https://snack.expo.io/uk8yb5xys
What I want is this:
The user is instructed to draw a line from the word "start" to the word "end". If the line is drawn and the start point and endpoint of the users line match the given path, they are then presented with another line to draw and the position of "start" and "end" will move so the user knows where to draw.
There is a comment line:
// HERE IS WHERE I NEED TO UPDATE THE VALUES FOR START AND END
This is where I need the word "start" and the word "end" to move to their new positions.
At the moment, when you draw a complete line and remove your finger from the screen - nothing happens. However, when you put your finger down the start and end do move. I need them to move when the user lifts up their finger.
I appreciate your time with this so thank you.
But useState doesn't return just a variable as the previous examples imply. This way, you can use the state variable in the functional component like any other variable: const Message = () => { const [message, setMessage] = useState( '' ); return ( <p> <strong>{message}</strong> </p> ); };
The useState hook is used to update the state in a React component. It is a hook that takes the initial state as an argument and returns an array of two entries. It can be used in a React class based component as well as a functional component (declared using the function or const keyword).
Sending state/props to another component using the onClick event: So first we store the state/props into the parent component i.e in which component where we trigger the onClick event. Then to pass the state into another component, we simply pass it as a prop.
Three options:
const setPositionFactory = (setPositionAX, setPositionAY) => (pos = 200) => {
setPositionAX(pos);
setPositionAY(pos);
}
So you can call it inside your component in many ways:
Directly:setPositionFactory(setPositionAX, setPositionAY)(); // default: 200
or Keeping the function for later use:
const setPosition = setPositionFactory(setPositionAX, setPositionAY);
// ...
setPosition(220);
App
and update state inside the component. It would be more idiomatic.Observable
with rxjs and subscribe your component to it.Adding observables to your question's code would be:
import { positionObs } from './observables';
const App () => {
const [positionAX, setPositionAX] = useState(100);
const [positionAY, setPositionAY] = useState(100);
positionObs.subscribe((pos) => {
setPositionAX(pos);
setPositionAY(pos);
});
}
Then in observables
import { Subject } from 'rxjs';
export const positionObs = new Subject();
export const setPosition = () => {
positionObs.next(200);
};
The state setters you get from useState
are specific to the component instance, created when the component function is called the first time.
You have a few options:
You can pass setPositionAX
and setPositionAY
into setPosition
as arguments.
You can put your setPosition
function in your component function. (Yes, it'll be recreated each time, but that's fairly harmless.)
You can create your own hook for position information.
#3 looks like this:
const usePosition = (_x = 0, _y = 0) => {
const [x, setX] = useState(_x);
const [y, setY] = useState(_y);
const {current: setPosition} = useRef(function setPosition(_x = 0, _y = 0) {
setX(x);
setY(y);
});
return [x, y, setPosition];
};
Then in your component function:
const [xA, yA, setPositionA] = usePosition(0, 0);
// ...
setPositionA(200, 200);
Or if you prefer a tuple for the position information:
const usePosition = ([_x = 0, _y = 0] = []) => {
// ^^^^^^^^^^^^^^^ ^^^^^−− optional default value
// \ \
// +−−−−−−−−−−−−+−−−−−−− destructuring
const [x, setX] = useState(_x);
const [y, setY] = useState(_y);
// (Ensure the setter is consistent across calls, like React does)
const {current: setPosition} = useRef(function setPosition([_x = 0, _y = 0] = []) {
setX(x);
setY(y);
});
return [ [x, y], setPosition ];
};
Then in your component function:
const [positionA, setPositionA] = usePosition([0, 0]);
// ^−−−−^−−−−− passing in a tuple
// ...
setPositionA([200, 200]);
Here's an example of that tuple version using React:
const { useState, useRef } = React;
const usePosition = ([_x = 0, _y = 0] = []) => {
const [x, setX] = useState(_x);
const [y, setY] = useState(_y);
const {current: setPosition} = useRef(function setPosition([_x = 0, _y = 0] = []) {
setX(x);
setY(y);
});
return [ [x, y], setPosition ];
};
const Example = () => {
const [positionA, setPositionA] = usePosition([0, 0]);
const handleClick = () => {
setPositionA([200, 200]);
};
return (
<div>
<div>Position: {positionA.join()}</div>
<input type="button" onClick={handleClick} value="Set 200x200" />
</div>
);
};
ReactDOM.render(<Example/>, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>
useState
allowing React to queue up the re-rendering of that specific component
you can pass APP.js function down to AnotherComponent and call App.js function from AnotherComponent and manage state on both component and other way to use REDUX if your structure is complex
you can test Snack Demo here: https://snack.expo.io/iVeYXymID
Fix according to edited question: https://snack.expo.io/i_RJHi0_v
import React, { useState, useRef } from "react";
import { Text, View, Button, StyleSheet } from "react-native";
const AnotherComponent = (props) => {
const [positionXY, setPositionXY] = useState(props.StateValue);
const handleClick = () => {
const value = [positionXY[0]+5, positionXY[1]+5];
setPositionXY(value);
props.setPositionValues(value);
};
return (
<View style={styles.anotherComponentStyle}>
<Text>
AnotherComponent PositionX: {positionXY[0]} PositionY: {positionXY[1]}
</Text>
<Button onPress={handleClick} title="Update Position"></Button>
</View>
);
};
const Sandbox = () => {
const StateValue = [0, 0];
const [positionXY, setPositionXY] = useState(StateValue);
const setPositionValues = (value) => {
setPositionXY(value);
};
return (
<View style={styles.container}>
<AnotherComponent setPositionValues={setPositionValues} StateValue={StateValue} />
<Text
style={{ positon: "absolute", top: positionXY[0], left: positionXY[1] }}
>
Sandbox component PositionX: {positionXY[0]} PositionY: {positionXY[1]}
</Text>
</View>
);
};
export default Sandbox;
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: "center", alignContent: "center" },
anotherComponentStyle: {
backgroundColor: "#eeeffe",
borderBottomColor: "#000000",
borderBottomWidth: 2,
marginBottom: 200,
justifyContent: "center",
alignItems: "center",
},
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With