React Native Picker moves back to first item - javascript

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]

Related

Clearing a Material UI search filter TextField and returning to default

I am new to ReactJS and pairing it with Material UI is really causing me some roadblocks. I have created a reusable search filter component for my data tables and it worked exactly the way I wanted, but now I want to add a button to clear the field and show the unfiltered results, as well as return the InputSearch component back to its default state so it will display the label inside the field again, not up in the field’s border as these Material UI TextFields do then they are focused or have a current value. This is where I am hitting my roadblock. I have tried multiple solutions I found online, like using the inputRef/useCallback method to change the values, but it didn’t seem to work…or maybe I misunderstood and did it wrong. I was also recommended to put my search values to state. As happens with state my searches are now always one render behind (I.E. , results matching ‘US’ for ‘USA’ , ‘USA’ for ‘USAF’, etc…). Then when I run the handleFilterReset function to set the filter values back to an empty string, nothing happens. I just want my search filter to work instantly (like it did before I moved the value to state [commented out]) and be able to be cleared, resetting the table back to its default display.
Can someone please help me figure this out? Suggestions are appreciated, but code snippets are much more helpful since I am really new to React and especially Material UI.
dataTable.js
const [inputValue, setInputValue] = useState('')
const [searchFn, setSearchFn,] = useState({ fn: items => { return items; } });
// Searching Data
const handleSearch = e => {
setInputValue(e.target.value) // value displayed in input field
let query = (e.target.value).toString().toLowerCase();
setSearchFn({
fn: items => {
if (query === "")
return items;
else
return items.filter(x =>
(x.tankName !== null && x.tankName.toLowerCase().includes(query)) ||
(x.dimensions !== null && x.dimensions.toLowerCase().includes(query))
)
}
})
}
// Clearing Filters
const handleFilterReset = () => {
setInputValue('');
setSearchFn({fn: items => {return items;}})
};
// Search and filter Inputs
<div>
<InputSearch
value={inputValue}
onChange={handleSearch}
/>
<Button
text="Reset"
onClick={handleFilterReset}
/>
</div>
InputSearch.js
export default function InputSearch(props) {
const { inputRef, name, value, error=null, onChange, ...other } = props;
return (
<TextField
label="Search..."
name={name}
value={value}
onChange={onChange}
{...other}
{...(error && {error:true, helperText:error})}
>
</TextField>
)
}
You need to pass the value to InputSearch
Heres an example:
https://codesandbox.io/s/morning-brook-durbvd?file=/demo.tsx
React has a pretty good introduction on its site.
https://reactjs.org/docs/components-and-props.html
The code has been updated with a solution to this issue. I created a display value for the input that I passed to state, which was set to a blank string when the reset is pressed as well as passing an unfiltered data set.

MUI DatePicker hangs on big date changes

MUI DatePicker (either from Labs or X) was working fine. I cannot work out what happened, but it now hangs if I want to change the date by ten years. It seems like the code goes into an infinite loop, but there's no output to the console. The code is
function DateSelector(props) {
const setValue = value => {
if (value !== null) {
const checked = checkDate(value);
props.handler(checked);
}
}
return (
<DatePicker
label={props.label}
inputFormat="d/M/y"
mask=""
value={props.date}
onChange={(value) => {
setValue(value);
}}
renderInput={(params) => (
<Tooltip title={"select " + props.label + " date"} arrow>
<TextField size="small" {...params} />
</Tooltip>
)}
/>
);
}
props.date is an App-level state that is handed down to the picker component. checkDate is a simple function to ensure the date is in the correct range (I've bug-tested it, and it's not the cause of the problem as far as I can see). props.handler changes the App-level state. I wonder if the problem is that I'm manipulating state at the App-level directly through the picker.
This is now resolved!
The problem here is that props.date is a date object stored as an App state that is passed to the component. The component is modifying this directly! Instead it should work with a deep copy of the date object.
Instead of
value={props.date}
it should have
value={new Date(props.date.getTime())}

React - How to iterate over an array of objects and display each item as a component?

I am using React and I have an array of data objects ("items"). I am trying to display this list of objects such that each object is its own component. So I'm calling "items.map" to map each item to a component and render it, like this:
return (
<Fragment>
<h1>Items</h1>
<Card.Group itemsPerRow={8} >
{items.length > 0 ? ( items.map( (_item) => (
<Fragment key={_item.key}>
<MyItem example={4} item={_item} />
</Fragment>
))
) : (<p>No items!</p>)}
</Card.Group>
</Fragment>
)
Here is the code for MyItem:
const MyItem = (example, item) => {
console.log(example);
console.log(item);
return (<Fragment>
<div style={{margin: "1em"}}>
<Card>
<Image src={item.image} wrapped ui={false} />
<Card.Content>
<Card.Header>{item.name}</Card.Header>
<Card.Description>
<p>Date Received: {item.dateReceived.toLocaleDateString()}</p>
</Card.Description>
</Card.Content>
</Card>
</div>
</Fragment>);
}
However, I'm getting an error saying that "item" is null in MyItem.js, while the list of items is definitely not null. Similarly, when I pass in the number 4 to the "example" prop, and I do "console.log(example)" it prints out the empty object "{}".
I should note that my page previously did display everything when both pieces of code were combined on the same page (i.e. there was no "MyItem" component). The reason I decided to make it a component was because I'm iterating over this map on multiple pages and it would be redundant code. This way, I can just call <MyItem item{_item} /> and it will display the same thing on every page that shows these items.
However, now that I have refactored my code to place the mapping inside of the component, it is no longer working. What am I doing wrong here? Is this even possible, or should I just go back to what I had before?
As mentioned in the above comment:
const MyItem = ({example, item})
This solves the problem.

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

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]

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 //
}

Categories