Three options:
A. Send those functions as params and use curried functions:
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);
B. Get those values as props of App and update state inside the component. It would be more idiomatic.
C. Use an 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);
};
Answer from Ignacio Lago on Stack OverflowReact Native - how to use 'useState()' in another function
How to useState in react native? - Stack Overflow
What is useState() in React?
What problem does useState in React solve?
Videos
Three options:
A. Send those functions as params and use curried functions:
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);
B. Get those values as props of App and update state inside the component. It would be more idiomatic.
C. Use an 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
setPositionAXandsetPositionAYintosetPositionas arguments.You can put your
setPositionfunction 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>
React hooks are a new way (still being developed) to access the core features of react such as state without having to use classes, in your example if you want to increment a counter directly in the handler function without specifying it directly in the onClick prop, you could do something like:
...
const [count, setCounter] = useState(0);
const [moreStuff, setMoreStuff] = useState(...);
...
const setCount = () => {
setCounter(count + 1);
setMoreStuff(...);
...
};
and onClick:
<button onClick={setCount}>
Click me
</button>
Let's quickly explain what is going on in this line:
const [count, setCounter] = useState(0);
useState(0) returns a tuple where the first parameter count is the current state of the counter and setCounter is the method that will allow us to update the counter's state. We can use the setCounter method to update the state of count anywhere - In this case we are using it inside of the setCount function where we can do more things; the idea with hooks is that we are able to keep our code more functional and avoid class based components if not desired/needed.
I wrote a complete article about hooks with multiple examples (including counters) such as this codepen, I made use of useState, useEffect, useContext, and custom hooks. I could get into more details about how hooks work on this answer but the documentation does a very good job explaining the state hook and other hooks in detail.
update: Hooks are not longer a proposal, since version 16.8 they're now available to be used, there is a section in React's site that answers some of the FAQ.
useState is one of build-in react hooks available in 0.16.7 version.
useState should be used only inside functional components. useState is the way if we need an internal state and don't need to implement more complex logic such as lifecycle methods.
const [state, setState] = useState(initialState);
Returns a stateful value, and a function to update it.
During the initial render, the returned state (state) is the same as the value passed as the first argument (initialState).
The setState function is used to update the state. It accepts a new state value and enqueues a re-render of the component.
Please note that useState hook callback for updating the state behaves differently than components this.setState. To show you the difference I prepared two examples.
class UserInfoClass extends React.Component {
state = { firstName: 'John', lastName: 'Doe' };
render() {
return <div>
<p>userInfo: {JSON.stringify(this.state)}</p>
<button onClick={() => this.setState({
firstName: 'Jason'
})}>Update name to Jason</button>
</div>;
}
}
// Please note that new object is created when setUserInfo callback is used
function UserInfoFunction() {
const [userInfo, setUserInfo] = React.useState({
firstName: 'John', lastName: 'Doe',
});
return (
<div>
<p>userInfo: {JSON.stringify(userInfo)}</p>
<button onClick={() => setUserInfo({ firstName: 'Jason' })}>Update name to Jason</button>
</div>
);
}
ReactDOM.render(
<div>
<UserInfoClass />
<UserInfoFunction />
</div>
, document.querySelector('#app'));
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<div id="app"></div>
New object is created when setUserInfo callback is used. Notice we lost lastName key value. To fixed that we could pass function inside useState.
setUserInfo(prevState => ({ ...prevState, firstName: 'Jason' })
See example:
// Please note that new object is created when setUserInfo callback is used
function UserInfoFunction() {
const [userInfo, setUserInfo] = React.useState({
firstName: 'John', lastName: 'Doe',
});
return (
<div>
<p>userInfo: {JSON.stringify(userInfo)}</p>
<button onClick={() => setUserInfo(prevState => ({
...prevState, firstName: 'Jason' }))}>
Update name to Jason
</button>
</div>
);
}
ReactDOM.render(
<UserInfoFunction />
, document.querySelector('#app'));
<script src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<div id="app"></div>
Unlike the setState method found in class components, useState does not automatically merge update objects. You can replicate this behavior by combining the function updater form with object spread syntax:
setState(prevState => { // Object.assign would also work return {...prevState, ...updatedValues}; });
For more about useState see official documentation.
Im not good in javascript and we started doing React in school.
Ive seen countless videoes on useState and read about it, but i dont get what problem its trying to solve. They all just say how to use it, not why to use it. It just seems like a variable with extra steps.
Like if i wanted to make a counter, i could:
const [count, setCount] = useState(0)
Now i have a variable, with an initial value, and which i can only update with a function (for some reason, why is that smart?).
Why wouldnt i just write:
Let count = 0
Shouldnt that suffice? I can add and subtract to that too, and i dont need a specific function to do so. When i refresh the page, both values resets regardless.
- You need to import useState and useEffect from React, not React Native
- You cannot call .then() on useEffect since it does not return a promise.
- You can't use useEffect as a callback function.
EDIT: Code example:
Based on the snippet from your question, it seems like you're trying to trigger a POST request to your database on submitting the text input. This can be achieved without useEffect by simply passing a handler function to your text input like so.
import React, { useEffect, useState } from 'react';
import { View, StyleSheet,TextInput } from 'react-native';
import db from 'D:/App development/PRLog/PrLogBeta/database/firestore'
const EnteryModal = props => {
const [numReps,setNumReps] = useState('');
const handleSubmit = async () => {
try {
await db.collection('Bench').add({reps:{newNum}});
console.log('Number Added!');
} catch (error) {
console.log(error)
}
}
return(
<View style={styles.inputStyle}>
<form>
<TextInput
style = {styles.inputStyle}
keyboardType='number-pad'
placeholder={props.RepsOrWeight}
placeholderTextColor = 'white'
textAlign='center'
onChangeText={newNum => setNumReps(newNum)}
defaultValue={numReps}
onSubmitEditing={handleSubmit}
>
</TextInput>
</form>
</View>
);
};
Use useState and useEffect as a react component not as react native component.
as shown in below example.
import React, { useEffect, useState } from 'react';
import { View, StyleSheet, TextInput} from 'react-native';
import db from 'D:/App development/PRLog/PrLogBeta/database/firestore'
const EnteryModal = props => {
const [numReps, setNumReps] = useState('');
useEffect(() => {
dataBaseCollection();
console.log("Number Added!");
}, []);
const dataBaseCollection = () => {
db.collection('Bench').add({ reps: { newNum } });
}
return (
<View style={styles.inputStyle}>
<form>
<TextInput
style={styles.inputStyle}
keyboardType='number-pad'
placeholder={props.RepsOrWeight}
placeholderTextColor='white'
textAlign='center'
onChangeText={newNum => setNumReps(newNum)}
defaultValue={numReps}
onSubmitEditing={(event) => {
dataBaseCollection();
}}
>
</TextInput>
</form>
</View>
);
};
You need to structure your state in a way that it is accessible to the components that need it. React likes you to have state in a component thats 'higher' in the tree than the components that need it, you can look at https://reactjs.org/docs/lifting-state-up.html for this.
Otherwise you could use the Context API or a 'global' store like Redux.
Logged in user data is a good candidate for the likes of Context or Redux, that way you will have access to the likes of username in any part of the application that is within your Context / Redux provider that provides the logged in data (or whatever other global data you may have)
You colud pass parameters to Home screen using navigation.navigate function in this way:
function logIn({ navigation }) {
const [username, setUsername] = useState('');
return (
<View style={{ backgroundColor: "white"}} >
<View>
<TextInput style={styles.input} placeholder='username' placeholderTextColor='white' textAlign='center' onChangeText={(val) => setUsername(val)} />
</View>
<View>
<Button title="Go to Home" onPress={() => navigation.navigate('Home', {username: username})} />
</View>
</View>
);
}
Then in HomeScreen:
function HomeScreen({ navigation, route }) {
return(
<View style={{ flex:1, alignItems: 'center', justifyContent: 'center'}}>
<Text>Welcome {route.params.username}</Text>
</View>
);
}