How to display data.lenght = 0 - javascript

My app allows the user to get pictures based on a date range. 1 picture per day (ex: start date 2021-01-01, end date 2021-01-04 = 4 pictures).
So, I would like to display the number of pictures shown based on the chosen date range.
The issue is that if I use data.lenght I will get the correct amount of pictures once the user chooses a date range, however, before the user chooses anything data.lenght = 1 and not 0 zero!
I also tried using item.lenght which returns a undefined value and calculating '(end date) - (start date) = result' but I get a Nan value.
The goal is to display Results = (0) before the user searches a data range and display Results = (number of pics on a given date range) once the user makes a search.
Here is the code:
const searchDateRange = async () => {
const api = await fetch(
`my api`
);
const data = await api.json();
setData(data);
};
then I display this:
<Text style={styles.resultsText}>Results ({data.length})</Text>
</View>
<View style={styles.imageGrid}>
<FlatList
data={data}
keyExtractor={(item, index)=>{return item.date}}
numColumns={numberOfCols}
renderItem={({item, index})=>(
<View style={styles.viewpic}>
<TouchableOpacity onPress={() => navigation.navigate('ImageDetails', item)}>
<Image
style={{
height: 115,
width: square - 12,
margin:6,
}}
source={{uri:item.url}}/>
</TouchableOpacity>
</View>
thanks everyone for your help!
Cheers!

Related

How to calculate difference between two moments in react native

I'm trying to calculate the duration (difference between two moments) for example currently I'm working on a react native project in which I have to calculate the time spent on a screen/card.
So right now I'm trying to calculate time spent like this:
import moment from 'moment';
// lets say i have 3 states to note time
const [startTime, setStartTime] = useState(moment());
const [endTime, setEndTime] = useState(moment());
const [elapsedTime, setElapsedTime] = useState(Number);
// assume i have a bottomSheet, so whenever that bottom sheet goes up the timer starts and when it goes down to original position, timer stops and calculate difference/duration in minutes.
// so for the onOpenStart on onCloseEnd props of the bottomsheet, this is my function:
const start = () => {
setStartTime(moment());
}
const end = () => {
setEndTime(moment());
const et = moment.duration(endTime.diff(startTime)).asSeconds();
setElapsedTime(et);
console.log(elapsedTime) // if i try for 10 seconds it logs 34, or sometimes -6, it's just not right
}
I tried to do with new Date method and if i try for 10 seconds it logs 34, or sometimes -6, it's just not right but could not succeed...
Any help would be appreciated.
In your particular case, I don't think you even need moment library. It's super heavy in the bundle and it's just not needed.
You don't need to initialise the state with the dates. You don't care about them when the component just mounts, do you? You want to keep track of the dates when your functions start and end get triggered.
The current behaviour is that way because useState is async. That means that you're trying to to set the state and then use this value in the next line for some calculation - that just won't work.
What you can do is to use useRef instead of useState. This way you will make sure that the value that you have is the freshest one across your component.
const startTime = useRef(new Date());
const endTime = useRef(new Date());
const [elapsedTime, setElapsedTime] = useState();
const start = () => {
startTime.current = new Date();
}
const end = () => {
endTime.current = new Date();
const et = (startTime.current - endTime.current) / 1000 // get the seconds
setElapsedTime(et);
console.log(et); // You cannot log elapsedTime here, because again, useState is async
}
I don't know what you need to do with the elapsed time, you might not need the state either. For now I've left it as state.
Last thing: I really recommend looking at day.js library, as it does the same things (in 99% of cases) as moment, but is much much lighter.
useState does not update synchronously. This means that although you setEndTime and then try to read it, the chances are it has not been updated yet.
Also, setting state causes a re-render. This is unnessasary when measuring performance. You can instead use useRef to hold the timing value in a reference variable.
export default function App() {
const [visible, setVisible] = React.useState(false);
const timer = React.useRef(null)
return (
<View style={styles.container}>
<Pressable
onPress={() => {
timer.current = new Date().getTime()
setVisible(true);
}}>
<Text>Show modal</Text>
</Pressable>
<Pressable
onPress={() => {
setVisible(false);
alert(new Date().getTime() - timer.current)
}}>
<Text>Hide modal</Text>
</Pressable>
{visible ? (
<Card>
<Text>Modal content</Text>
</Card>
) : null}
</View>
);
}
Here, we are setting the visible value and storing timestamp on press. And when the user presses hide, we use the stored time to calculate the time elapsed.

How to keep previous data and add more data in array React Native

I'm using picker with numbers 1 to 4, when the user selects any number from picker like I select 3 then 3 text inputs will be shown and I will enter something in these three input fields, and I'm saving values of these 3 inputs in an array. When I hit save and I want to edit it again like I've changed my mind and I want to add 2 more input fields and when I select 2 than the previous 2 replace with new 2 empty text inputs but I want to keep the previous as well.
Here are the screenshots
here is the code.
For a number of text input based on picker value.
{this.state.storeArr.map((item, index) => (
<TextInput
key={index}
style={[
styles.input,
{backgroundColor: theme.colors.lightGray},
]}
placeholder=" Name "
keyboardType={'default'}
placeholderTextColor="gray"
value={item}
onChangeText={(text) => this.onChangeText(text, index)}
/>
))}
onChangeText = (text, index) => {
const {storeArr} = this.state;
const arr = [...storeArr];
arr[index] = text;
this.setState({storeArr: arr}, () => {
console.log(this.state.storeArr);
});
console.log(storeArr);
};
here is the code of setting no of "" in the array based on picker value
setInput = (value) => {
this.setState({storeArr: Array(value).fill('')});
};
in setinput function I want to handle to keep the previous strings in the array and add more as per picker value selected using Array(value).fill('')
Try this for the setInput function:
setInput = (value) => {
this.setState({ storeArr: value - this.state.storeArr.length >= 0
? [...this.state.storeArr, ...Array(value - this.state.storeArr.length).fill('')]
: this.state.storeArr.filter((_, index) => index <= value)
});
};

Get y-offset value of all views inside Flatlist

I am rendering atleast 5 View inside a Flatlist. I am trying to store the y-offset value of each view inside a state array. But the value that the state receives is 0. How do I make sure that I get the correct y-offset value saved to my state array?
Here is my code
<Flatlist
data={data}
renderItem = {({ item }) => {
return (
<View
onLayout={event => this.setState({ yArray : [...this.state.yArray, event.nativeEvent.layout.y] })}
>
<Text>Something</Text>
</View>
)
}}
/>
When I do console.log(this.state.yArray), it output [0]
I expected it to be something like [30, 80, 130, ...]
So, there are two issues:
1. The y offset is always 0
2. y offset values aren't pushed into the array.

javascript React Native

Hi (Sorry for my english)
I have a problem, I consume a service that bring me a buttons array for a dynamic menu. This array I want to put in the screen, like button have a id for a action in specific.
Code
var sizes = []
for (var i = 0; i < this.state.tallas.length; i++) {
sizes.push(
<TouchableOpacity style={[styles.clothingSizeItem, this.state.idSize === this.state.tallas[i].id ? styles.activeClothingSizeItem:null]}
onPress={() => this.fetchSizeData(this.state.tallas[i].id)}>
<Text style={this.state.idSize === this.state.tallas[i].id ? styles.activeSizeText:null}>
{this.state.tallas[i].name}
</Text>
</TouchableOpacity>
);
}
View
render() {
return(
{sizes}
)
}
The problem is when I press a button from my dinamic menu, the button call a function that receive a parameter, but this parameter comes from service array. So I use "i" param from for, but this variable ("i") can't found after that the screen was rendered.
Screen Shot
error screen
Gracias!
You can use Array#map instead of a for loop:
const sizes = this.state.tallas.map(item => (
<TouchableOpacity style={[styles.clothingSizeItem, this.state.idSize === item.id ? styles.activeClothingSizeItem:null]}
onPress={() => this.fetchSizeData(item.id)}>
<Text style={this.state.idSize === item.id ? styles.activeSizeText:null}>
{item.name}
</Text>
</TouchableOpacity>
);
The reason the for loop doesn't work here is that the index variable i is incremented on every iteration of the loop, so by the time the callback ends up being called (long after the loop has completed), the value i is always it's final value (same as tallas.length).

How to scroll to a specific object using scrollTo() in ScrollView?

I render several sections and one of the sections is a ScrollView. This ScrollView is a horizontal days calendar and each item is arenderRow() that and has View Text and Button wrapped together within one View:
render()
{
//..
let day = this.renderDaysView();
return(
<View style={{ backgroundColor: 'white' }}>
{day}
</View>
)
}
renderDaysView()
{
let renderRow = (rowData, rowID) => {
return (
<View key={rowID}>
<TouchableOpacity ... >
<View ... >
<Text ... >{currentWeekDay}</Text>
</View>
</TouchableOpacity>
</View>
);
}
return (
<ScrollView ref={(scrollview) => this._daysScrollView = scrollview} horizontal= 'true'>
{
this.state.Days.map((item, index) => renderRow(item, index) )
}
</ScrollView>
}
}
Now, when the screen gets displayed, I would like todays day to be right in the middle of the screen.
Following the Docs, scrollTo() can take an object:
scrollTo( y? , object , x?, animated? )
Currently I am using this hack (which is missing one part) where I multiply the current day of month with a specific value:
componentWillUpdate(newProps: Object, newState: Object) {
this._daysScrollView.scrollTo(
{
x: // if first week, do nothin
newProps.currentDate.getDate() < 6 ?
0
: // elseif if last week, scroll to scrollView width (missing)
newProps.currentDate.getDate() > 27 ?
(newProps.currentDate.getDate() * 55 ) - ( 7 * 52) // TODO: should be scrollview width
: // else someday later, put in in the middle
(newProps.currentDate.getDate() - 4) * 55,
animated: true
}
)
}
So I either need to know the width of _daysScrollView, or jump to that object - 4 (to keep it in middle)
If my object is a component, how can I jump to a specific object? (For ex. if today is the 19th, go to index 19)
Or for my hack,
How can I get the width of my _daysScrollView?(_daysScrellView.width) did not work
Thanks
To use the scrollTo method you would have to get the x/y position of the element you wanted to scroll to. An easier solution might be something like this:
componentDidUpdate() {
let location = window.location;
let dayOfMonth = new Date.getDate();
location.hash = `#${dayOfMonth}`;
}
The new Date.getDate(); will return a number 1 - 31 depending on the day in the month. So if you set the id of each day in your calendar to a number corresponding to its day in the month. The above will scroll to it.
location.hash = `#${dayOfMonth}`;
will then scroll the document to the element with that id attribute.
Set the id of each day to the it's numerical position in the month and window.location.hash to route to the anchor of the day within the page.
EDIT: Try replacing your componentWillUpdate() method with this componentDidUpdate.

Categories

Resources