React-native using a state variable while getting data from fetch - javascript

I'm trying to create a simple Expo Snack that converts between two currencies the user picks.
I have two state variables that are updated when someone picks an option from a dropdown list, and I want to use the value of those state variables to get data from a fetch.
<Picker
selectedValue={this.state.curr1}
style={{ height: 25, width: 125 }}
onValueChange={(itemValue, itemIndex) => this.setState({ curr1: itemValue })}>
<Picker.Item label="US Dollar" value="USD" />
<Picker.Item label="Euro" value="EUR" />
</Picker>
So here I'm setting the value of the state variable to either USD or EUR.
convert() {
fetch('https://open.exchangerate-api.com/v6/latest')
.then((response) => response.json())
.then((json) => {
const currency1 = this.state.curr1;
const currency2 = this.state.curr2;
alert(currency1);
alert(currency2);
const currRate1 = json.rates.currency1;
const currRate2 = json.rates.currency2;
alert(currRate1);
alert(currRate2);
And this is where I'm stuck. The first alerts (Currency1&2) show that the values are USD and EUR.
But when trying to use them to call the rates in the second half I get "undefined" for both.
If I do
json.rates.EUR;
json.rates.USD;
it calls the rates correctly. Can't figure out exactly how to format this so I can use the state variables from the pickers to call the rates.

You are getting undefined because the values of currency1 and currency2 are strings. To use these values as properties you should add brackets:
json.rates.[currency1]
json.rates.[currency2]

Related

React controlled component not resetting to an empty string

I have a <TextField> component from Material UI that's supposed to allow a user to choose a numerical value. The field is for use on a medical product so we cannot have a default value that's displayed; rather, the value is initially an empty string and onInput we update it accordingly. The min/max props don't work as needed when passed to InputProps, so we manually check if the value passed is less than or equal to zero ('-' also evaluates to true here), and if so we reset the value to 1. However, when I try to instead reset the value to an empty string (i.e. clear the input), the actual state value changes, but the text displayed in the TextField component remains the same for some reason. If anyone knows why the text displayed is not clearing and what I could do to fix this, please let me know!
Code below:
<TextField
disabled={!!requirement.id}
type="number"
value={requirement.val}
variant="outlined"
InputProps={{ inputProps: { min: 1, max: 1000000 } }}
placeholder={'Title!'}
onInput={(e) =>
handleRequirementChange(
Number(e.target.value),
index
)}
/>
const handleRequirementChange = (val, index) => {
const requirement = [...requirement]
if (val <= 0) val = 1
requirement[index] = val
setRequirement(requirement)
}

React: useState/useEffect - How to collect 10 items in realtime

I am trying to get 10 usernames back when I type a keystroke.
For now it only gives me a Username back if the username is exactly in the jsonplaceholder list. So when i type "Karia" nothing comes back until I type "Karianne"
So for example if the Input gets the first letter "A", I want to give back the first 10 Items which are matching from the jsonplaceholder list. If I put in an "R", after that, so its "Ar" I want to get back the first 10 matching "Ar" usernames, like Aron, Ariel, Aria, etc.
Does someone have an Idea?
export const Search = () => {
const [user, setUser] = useState(null);
const [searchQuery, setSearchQuery] = useState("")
useEffect(() => {
if (searchQuery.length > 0) {
const fetchFunc = async () => {
const response = await fetch(`https://jsonplaceholder.typicode.com/users?username=${searchQuery}`)
const resJSON = await response.json();
setUser(resJSON[0]);
};
fetchFunc();
}
}, [searchQuery]);
return (
<Flex className={styles.search__container}>
<Flex className={styles.search__elements}>
<InputGroup className={styles.search__input}>
<InputRightElement
className={styles.search__inputElements}
children={<RiSearchLine className={styles.search__icon} />} />
<Input
className={styles.search__users}
type='search'
placeholder='Search'
onChange={event => setSearchQuery(event.target.value)}
/>
{user ? (
<div>
<h3>{user['name']}</h3>
<h3>{user['username']}</h3>
<h3>{user['email']}</h3>
</div>
) : (
<p>No user found</p>
)}
</InputGroup>
</Flex>
</Flex>
)
}
The main limitation here is on the API side. Your API should supply you with the similar names. If it doesn't, then you can't do much.
Maybe the API provides a way to retrieve users with partial names (but I doubt it would be the case).
Otherwise, you can retrieve all users once,and simply display the one that fits your requirements, every time you write something.
To sum up:
When your component is mounted (at the beginning), fetch all users, and store them. You will perform this API call only once.
Then, every time you write something, just take the 10 users that have a name that include what you wrote.
Ideally, this should be handled by the API, and you should be concerned about when to trigger or re-trigger the API call.
API gets you a list of names, you slice a set of 10 from the list of names and set it in users, and then simply map them in your UI.
Also, you could maybe further optimise the function debouncing the API call.

Editing text input with static data on react native

When using text input using this.state it doesn't matter to give value a state variable and you'll able to edit the value, in my case here I am rendering a list and when I specify value of text input I can no longer edit that value because it's outside the state, I don't want to use placeholder to show the value, I need a way to have it as value but also be able to edit that value.
<TextInput
keyboardType='decimal-pad'
value={String(roomData.room_attached_dimensions.depth)}
onChangeText={(value) => this.handleRoomEdit(value)}
/>
Also I don't understand why should I wrap my values with String, it shows nothing otherwise.
My list looks like so
const attachedRooms = this.state.rooms_attached.map((item, index) => (
<View key={index}>
...
</View>
))
The function does nothing special
handleRoomEdit = (value) => {
this.setState({ roomEdit: true, value: value })
}
Of course I have different inputs I cannot simply give them different names, the data is stored on asyncStorage and even if I edit the array it dont work unless I re mount the damn component
Okay there's you error. You are not handling your input's value with state. That's why it does not work. You can do something like this -
<TextInput
keyboardType='decimal-pad'
value={this.state.value || String(roomData.room_attached_dimensions.depth)}
onChangeText={(value) => this.handleRoomEdit(value)}
/>
I think this should work. Now you are handling your input's value with state. Or you can use defaultValue to give initial value, but I think react discourages using defaultValue and Value both -
<TextInput
keyboardType='decimal-pad'
defaultValue={String(roomData.room_attached_dimensions.depth)}
value={this.state.value}
onChangeText={(value) => this.handleRoomEdit(value)}
/>
EDIT:: Also you can use ES6 to make your code clean -
handleRoomEdit = (value) => {
this.setState({ roomEdit: true, value }) //use ES6 shorthand //
}

Swap values of two TextFields in Reactjs (material-ui)

I have a functional component that contains user input and it is child of a class component which contains the state with the input. In the child functional component I want a function that can swap values between two TextFields(https://material-ui.com/api/text-field/).
What I have tried so far:
<TextField
id="outlined-from"
label="Από"
className={classes.textField3}
value={transport_detail[idx].from}
onChange={handleDynamicChange('from', idx)}
ref={x => from = x}
/>
<IconButton onClick={()=>{
var temp = from.value;
console.log(temp)
from.value = to.value;
to.value = temp;
}}>
<SyncIcon/>
</IconButton>
<TextField
id="outlined-to"
label="Προς"
className={classes.textField3}
value={transport_detail[idx].to}
onChange={handleDynamicChange('to', idx)}
ref={x => to = x}
/>
I tried using ref, but as I see from the docs it is only used with class components.
Anyone has any solution to this?
Since you are already saving the values of the textfields in the state, you can remove the ref and just change, how you save the texts. This will let you easily swap the contents.
Here is a sandbox, to show you the final result.
Just like in your example, the functional component gets the values and the handleDynamicChange function. This will populate the textfields and updates on changes of the text.
The button simply calls handleDynamicChange for each value with the opposing key:
handleDynamicChange("to", idx)({ target: { value: transport_detail[idx].from} });
handleDynamicChange("from", idx)({ target: { value: transport_detail[idx].to} });
This will set the value of the from text field to the value of the to textfield and vice versa.
Obviously, you need to adjust the values to fit your data structure, but this should work, without the need of refs.

React Native Picker moves back to first item

This works as expected, where the picker stays on the selected item...
<Picker
selectedValue={this.state.person}
onValueChange={(itemValue) => this.setState({person: itemValue})}
style={styles.picker}>
{Object.keys(coWorkers)
.map((result, index) =>
<Picker.Item
label={`${coWorkers[result].name}(${coWorkers[result].likes})`}
value={coWorkers[result].name}
key={index}
/>
)
}
</Picker>
I want to get multiple key/values from the coWorkers object in this.setState, so I am trying this...
<Picker
selectedValue={this.state.person}
onValueChange={(itemValue) => this.setState({person: itemValue.name, likes: itemValue.likes})}
style={styles.picker}>
{Object.keys(coWorkers)
.map((result, index) =>
<Picker.Item
label={`${coWorkers[result].name} (${coWorkers[result].likes})`}
value={coWorkers[result]}
key={index}
/>
)
}
</Picker>
However, now the picker jumps back to the top (this.state is being correctly updated though).
The type of the prop value for the Picker should be either string or integer. It is not clear from the docs on the website but you can see it in the Picker source code comments here https://github.com/facebook/react-native/blob/master/Libraries/Components/Picker/Picker.js
It does a simple equal check of selectedValue and picker items value to translate it to the native PickerIOS understands. https://github.com/facebook/react-native/blob/master/Libraries/Components/Picker/PickerIOS.ios.js#L53
Although the contents are same the object this.state.selectedValue and matching coWorkers[result] are different objects
You can generate some unique ids for each item in the array and use that to lookup the object.
If someone else has this problem and the solutions above are not working, it might be because you don't have the selectedValue flag set to something:
// You can replace the null with an actual value in your array(check to see it's exact)
const [toLanguage, setToLanguage] = useState(null);
selectedValue={toLanguage}
Your itemValue.name is not matching your coWorkers[result]

Categories