I have an array of objects. Each object has time and status. Also, I have a range of time with a specific value and I needed to display that on the timeline:
I want the result something like that
I suppose need to use "react-native-svg" and "react-native-svg-charts", but I can't understand how to make the timeline.
If you can, suggest a solution, please.
I've resolved this:
import React from "react";
import PropTypes from "prop-types";
import {StyleSheet, View} from "react-native";
import Icons from "react-native-vector-icons/MaterialIcons";
import {LineChart, Path} from "react-native-svg-charts";
import {ClipPath, Defs, ForeignObject, G, Rect} from "react-native-svg";
import {connect} from "react-redux";
import * as shape from "d3-shape";
import colors from "../../../styles/colors";
const TimeLine = (props) => {
// props.info.distractions - the array of red lines on the timeline (green line)
const startTime = props.info.startTs; // the start value of the timeline (GREEN line)
const endTime = props.info.endTs; // the end time value of the timeline (GREEN line)
const data = [0, 0];
const line = shape.curveBasis;
// Get coefficients to scale the array of red lines into the timeline (green line)
const getCoefficients = (distraction) => {
const wholeTime = endTime - startTime;
const dZone = distraction;
const a1 = dZone.start - startTime;
const a2 = dZone.end - endTime;
const startCoefficient = a1 / wholeTime;
const endCoefficient = a2 / wholeTime;
return {startCoefficient, endCoefficient};
};
// To render a red line on the timeline (green line)
const RenderLine = ({width, distraction, index}) => {
const {startCoefficient, endCoefficient} = getCoefficients(distraction);
return (
<ClipPath id={`clip-path-${index + 1}`}>
<Rect
x={startCoefficient * width}
y={"0"}
width={endCoefficient * width}
height={"100%"}
/>
</ClipPath>
);
};
// To render a red line on the timeline (green line)
const DistractionLine = ({line, index}) => {
return (
<G key={index}>
<Path
key={`line-${index + 1}`}
d={line}
stroke={colors.red}
strokeWidth={6}
fill={"none"}
clipPath={`url(#clip-path-${index + 1})`}
/>
</G>
);
};
// To render an icon
const ChartPoint = ({width, distraction, index}) => {
const {startCoefficient, endCoefficient} = getCoefficients(distraction);
return (
<ForeignObject
x={(startCoefficient * width + endCoefficient * width) / 2}
y={40}
width={100}
height={40}>
<Icons name={"touch-app"} color={colors.red} size={24} />
</ForeignObject>
);
};
// To render the timeline (green line)
const Clips = ({x, y, width}) => {
return (
<Defs key={"clips"}>
<ClipPath id="clip-path-0">
<Rect x={"0"} y={"0"} width={width} height={"100%"} />
</ClipPath>
{props.info.distractions.map((distraction, index) => (
<RenderLine
key={index}
index={index}
distraction={distraction}
width={width}
/>
))}
</Defs>
);
};
return (
<View style={styles.chartContainer}>
<Icons
name={"radio-button-checked"}
size={24}
color={colors.red}
style={{marginRight: -2, marginBottom: 10}}
/>
<LineChart
style={{height: 70, width: "90%"}}
data={data}
contentInset={{top: 0, bottom: 40}}
curve={line}
svg={{
stroke: colors.green,
strokeWidth: 6,
clipPath: "url(#clip-path-0)",
}}>
<Clips />
{props.info.distractions.map((distraction, index) => (
<ChartPoint
key={index}
index={index}
distraction={distraction}
/>
))}
{props.info.distractions.map((distraction, index) => (
<DistractionLine
key={index}
index={index}
distraction={distraction}
/>
))}
</LineChart>
<Icons
name={"place"}
size={24}
color={colors.red}
style={{marginLeft: -6, marginBottom: 10}}
/>
</View>
);
};
TimeLine.defaultProps = {
info: {},
};
TimeLine.propTypes = {
info: PropTypes.object,
};
const styles = StyleSheet.create({
chartContainer: {
marginTop: 20,
flexDirection: "row",
padding: 20,
paddingVertical: 20,
backgroundColor: "#fff",
justifyContent: "center",
alignItems: "center",
},
});
const mapStateToProps = (state) => {
const { infoReducer } = state;
return {
info: infoReducer.info,
};
};
export default connect(mapStateToProps)(TimeLine);
Related
In ReactNative, the bottomsheet is displayed overlaid on the fragment.
Is there a way to make the bottomsheet rise to the top of the screenenter image description here
The bottom sheet looks opaque as in the picture, so the bottom sheet cannot be touched Please help
The code below is a shortened version
enter image description here
enter image description here
import React, { FC , Component, useState, useEffect, Fragment,useCallback, useMemo, useRef } from "react"
import { FlatList, ViewStyle, StyleSheet, View, Platform, TextInput, TouchableOpacity} from "react-native"
import {
BottomSheetModal,
BottomSheetModalProvider,
BottomSheetBackdrop,
} from '#gorhom/bottom-sheet';
const ROOT: ViewStyle = {
backgroundColor: DefaultTheme.colors.background,
flex: 1,
}
export const ChecklookupScreen: FC<StackScreenProps<NavigatorParamList, "checklookup">> = observer(function ChecklookupScreen() {
const bottomSheetModalRef = useRef<BottomSheetModal>(null);
// variables
const snapPoints = useMemo(() => ['25%', '50%'], []);
// callbacks
const handlePresentModalPress = useCallback((index: string) => {
LOG.info('handlePresentModalPress', index);
bottomSheetModalRef.current?.present();
}, []);
const handleSheetChanges = useCallback((index: number) => {
LOG.info
console.log('handleSheetChanges', index);
}, []);
const renderItem = ({ item, index }) => (
<TouchableOpacity
key={index + item.inspNo + item.spvsNo}
//style={listContainer}
onPress={throttle(() => {
onClickItem(item.inspNo,item.spvsNo);
})}
>
<View>
<Fragment>
</View>
<Button icon="magnify-expand"
mode="elevated"
style={styles.detailButton}
onPress={throttle(() => {
onClickItem(item.inspNo,item.spvsNo);
})}
// onPress={() => navigation.navigate("checkdetail")}
>
</Button>
</View>
</Fragment>
</View>
</TouchableOpacity>
);
const fetchChecklookups = async (offset: number) => {
LOG.debug('fetchChecklookups:' + offset);
setRefreshing(true);
await checklookupStore.getChecklookups(offset)
setRefreshing(false);
};
const onEndReached = () => {
if (checklookupStore?.checklookupsTotalRecord <= checklookups?.length) {
LOG.debug('onEndReached555555555');
} else {
setPage(page + 1)
fetchChecklookups(page + 1);
}
};
const [searchQuery, setSearchQuery] = React.useState('');
const onChangeSearch = query => setSearchQuery(query);
return (
<Screen preset="fixed" style={{ backgroundColor: colors.background, flex: 1, padding: 10,}}>
<View style={{ flex: 1,}}>
<View style={{ flex: 1, }}>
<Searchbar
placeholder="조회조건을 입력해주세요"
onChangeText={onChangeSearch}
value={searchQuery}
onPressIn={() => handlePresentModalPress('touch on')}
/>
<BottomSheetModalProvider>
<BottomSheetModal
backgroundStyle={{ backgroundColor: "gray" }}
style={styles.bottomSheet}
ref={bottomSheetModalRef}
index={1}
snapPoints={snapPoints}
onChange={handleSheetChanges}
>
<View style={{ marginTop: 10, marginLeft: 50, marginRight: 50, flexDirection: "row"}}>
<View style={{ flex: 1, }}>
<Button
mode="outlined"
>소속을 입력하세요
</Button>
</View>
</View>
</BottomSheetModal>
</BottomSheetModalProvider>
</Screen>
)
})
You can try with portal, wrap you bottom sheet to from another package.
I am trying to add pagination function for the web in React Native. Essentially I have two issues.
I have linked the data to the page numbers, so it is calculating the number of pages correctly, but the pages don't change when I hit the arrow to the next page.
The page selection dropdown doesn't work. I can change the number in the code to show a specific number of items on the page, but not through the dropdown on the page.
Page Numbers changing when I manually change how many to display per page
I've included some of the code below that relates to this.
import React, { useEffect, useState } from 'react';
import { StyleSheet, ActivityIndicator, Text, View, FlatList, Modal, Dimensions } from 'react-native';
import Moment from 'react-moment';
import { DataTable } from 'react-native-paper';
import { AntDesign } from '#expo/vector-icons';
import TaskView from '../components/TaskView';
import { Switch } from 'react-native-paper';
import DropDownPicker from 'react-native-dropdown-picker'
import { RFValue } from "react-native-responsive-fontsize";
const window = Dimensions.get("window");
const screen = Dimensions.get("screen");
const numberOfItemsPerPageList = [1, 5, 10, 25, 50, 100];
function TaskList(props) {
const [isLoading, setLoading] = useState(true);
const [data, setData] = useState([]);
const [filteredData, setFilteredData] = useState([]);
const [modalVisible, setModalVisible] = useState(false);
const [dimensions, setDimensions] = useState({ window, screen });
const [id, setId] = useState('');
const moment = require('moment');
const [toggle, setToggle] = useState(false);
const [items, setItems] = useState([]);
const [value, setValue] = useState([]);
const [open, setOpen] = useState(false);
const [page, setPage] = useState(1);
const [numberOfItemsPerPage, onItemsPerPageChange] = useState(numberOfItemsPerPageList[1]);
const [currentPage, setCurrentPage] = useState(1);
const indexOfLastItem = currentPage * numberOfItemsPerPage;
const indexOfFirstItem = indexOfLastItem - numberOfItemsPerPage;
const currentItems = dataSet.slice(indexOfFirstItem, indexOfLastItem);
const dataLength = filteredData.length;
const totalPages = Math.ceil(dataLength / numberOfItemsPerPage);
return (
<View style={styles.mainContainer}>
<View style={styles.switchContainer}>
<Text style={styles.switchText}>Future Defer Dates:</Text>
<Switch value={toggle} onValueChange={toggleSwitch} />
</View>
<DropDownPicker
placeholder='Filter'
items={items}
open={open}
setOpen={setOpen}
value={value}
setValue={setValue}
multiple={true}
mode='BADGE'
badgeDotColors={["blue", "green", "red", "orange", "pink", "yellow", "brown", "violet"]}
onClose={filterData}
/>
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
Alert.alert("Modal has been closed.");
setModalVisible(!modalVisible);
}}
>
<View style={styles.modal}>
<View style={styles.closeCircle}>
<AntDesign name="closecircleo" size={26} color="black" onPress={() => setModalVisible(false)} />
</View>
<TaskView task={id} />
</View>
</Modal>
<DataTable>
**<DataTable.Pagination
page={page}
// onClick={}
totalItems={dataLength}
numberOfPages={totalPages}
onPageChange={page => setCurrentPage(currentPage+1)}
selectPageDropdown={numberOfItemsPerPageList}
label={`${currentPage} of ${totalPages} pages`} //text # of # pages
selectPageDropdownLabel={'Tasks per page'} //text next to task amount number drop down
numberOfItemsPerPageList={numberOfItemsPerPageList} //task amount number drop down
showFastPaginationControls //arrows to the first and last page
numberOfItemsPerPage={numberOfItemsPerPage}
onItemsPerPageChange={onItemsPerPageChange}
/>**
<DataTable.Header style={{ position: 'sticky', top: '0px', backgroundColor: "#eaeaea", zIndex: 1 }}>
<DataTable.Title><Text style={{ fontSize: 30, fontWeight: 'bold', position: 'absolute', color: 'black' }}>Task</Text></DataTable.Title>
<DataTable.Title><Text style={{ fontSize: 30, fontWeight: 'bold', position: 'absolute', color: 'black' }}>Due Date</Text></DataTable.Title>
<DataTable.Title><Text style={{ fontSize: 30, fontWeight: 'bold', position: 'absolute', color: 'black' }}>Status</Text></DataTable.Title>
<DataTable.Title><Text style={{ fontSize: 30, fontWeight: 'bold', position: 'absolute', color: 'black' }}>Category</Text></DataTable.Title>
</DataTable.Header>
{isLoading ? <ActivityIndicator /> : (
<FlatList
data={filterData()}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<DataTable.Row onPress={() => showModal(item.id)}>
<DataTable.Cell>
<AntDesign name="rightsquare" size={14} color="black" style={{ marginRight: 15 }} />
{item.name}
</DataTable.Cell>
<DataTable.Cell>
<Moment format="MMMM Do YYYY">{item.due_date}</Moment>
</DataTable.Cell>
<DataTable.Cell>
{item.status.status}
</DataTable.Cell>
<DataTable.Cell>
{item.category.name}
</DataTable.Cell>
</DataTable.Row>
)
}
/>
)}
</DataTable>
</View>
);
};
/>
I'm building a react-native screen in which I am having a Material Top Navigator. I don't know why the tab navigator is visible but the component inside it is not showing. I have imported the required dependencies. The component is rendering normally if used without tab navigator.
Main screen code:
import React,{useState,useEffect} from 'react';
import {View, Text,StyleSheet,Image,ScrollView,FlatList } from 'react-native';
import axios from 'axios';
import {Colors} from '../Components/Common/Colors';
import TeamvsTeam from '../Components/TeamvsTeam';
import Heading from '../Components/Common/Heading';
import EventItem from '../Components/EventItem';
import TeamLineup from '../Components/TeamLineup';
import { createMaterialTopTabNavigator } from '#react-navigation/material-top-tabs';
const FixtureDetails = ({route,navigation}) => {
const [fixturedetail,setfixture] = useState();
const {id} = route.params;
useEffect(()=>{
getfixturedetails(id);
},[]);
const getfixturedetails = (id) => {
console.log('Fixture Id -> '+id)
const options = {
method: 'GET',
url: 'https://api-football-v1.p.rapidapi.com/v3/fixtures',
params: {id: '157201'},
headers: {
'X-RapidAPI-Host': 'api-football-v1.p.rapidapi.com',
'X-RapidAPI-Key': '7eccf3c916msh125eb404409a0fcp1de117jsn811515176179'
}
};
axios.request(options).then(function (response) {
setfixture(response.data.response[0]);
console.log('fixturedetail '+fixturedetail.lineups[1].team.logo);
}).catch(function (error) {
console.error(error);
});
}
const renderPage = () => {
return fixturedetail ?
<ScrollView style={styles.parentview}>
<View
style={styles.leaguelogocontainer}
>
<Image
source={{uri:fixturedetail.league.logo}}
style={styles.leaguelogo}
/>
</View>
<View>
<TeamvsTeam
navigation = {navigation}
logohome={fixturedetail.teams.home.logo}
logoaway={fixturedetail.teams.away.logo}
homename={fixturedetail.teams.home.name}
awayname={fixturedetail.teams.away.name}
homescore={fixturedetail.goals.home}
awayscore={fixturedetail.goals.away}
homeid={fixturedetail.teams.home.id}
awayid={fixturedetail.teams.away.id}
/>
</View>
<Heading text="Events" />
<FlatList
data={fixturedetail.events}
horizontal={true}
renderItem={({item})=>{
return (
<EventItem
url = {item.team.logo}
name = {item.team.name}
timeelapsed = {item.time.elapsed}
extratime = {item.time.extra}
playername = {item.player.name}
asistname = {item.assist.name}
type = {item.type}
detail = {item.detail}
/>
);
}}
/>
{Lineup()}
</ScrollView>
:
<Text>Loading</Text>
}
const Lineup = () =>{
const Tab = createMaterialTopTabNavigator();
return fixturedetail.lineups.length>0 ?(
<Tab.Navigator
screenOptions ={{
tabBarStyle:{
backgroundColor:Colors.white,
borderRadius:8,
margin:16
},
tabBarLabelStyle: {
fontSize: 12,
color:Colors.black,
fontWeight:'bold',
},
}}
>
<Tab.Screen
name={fixturedetail.teams.home.name}
component={TeamLineup}
initialParams={{
index: 0,
lineup:fixturedetail.lineups
}}
/>
<Tab.Screen
name={fixturedetail.teams.away.name}
component={TeamLineup}
initialParams={{
index:1,
lineup:fixturedetail.lineups
}}
/>
</Tab.Navigator>
)
:
null;
}
return (
<View>
{renderPage()}
</View>
);
};
const styles = StyleSheet.create({
parentview:{
backgroundColor:Colors.mybackground,
width:'100%'
},
leaguelogocontainer:{
height: 150,
backgroundColor:Colors.white,
borderRadius:8,
margin:16
},
leaguelogo:{
height:'100%',
width:'auto',
minWidth:175,
alignSelf: 'center',
flexGrow:2,
alignItems: 'stretch',
flexDirection:'row'
},
});
export default FixtureDetails;
Component screen:
import React from 'react';
import {View, Text,StyleSheet,Image,FlatList } from 'react-native';
import { Colors } from './Common/Colors';
import Detail from './Common/Detail';
import Heading from './Common/Heading';
[![unable to scroll below this point][1]][1]const TeamLineup = ({route}) => {
const {index,lineup} = route.params;
console.log('logo '+lineup[index].team.logo);
return lineup.length>0 ? (
<View style={styles.parent}>
<Heading text="Lineups" />
<Image
style={styles.image}
source={{uri:lineup[index].team.logo}}
/>
<Text
style={styles.name}
>{lineup[index].team.name}</Text>
<Image
style={styles.image}
source={{uri:lineup[index].coach.photo}}
/>
<Text
style={styles.name}
>{lineup[index].coach.name}</Text>
<Text
style={styles.name}
>Team</Text>
<FlatList
style={styles.flatlist}
data={lineup[index].startXI}
renderItem={({item,index})=>{
var i = index+1;
return (
<Detail
title={i}
value={item.player.name}
/>
);
}}
/>
<Text
style={styles.name}
>Substitutes</Text>
<FlatList
style={styles.flatlist}
data={lineup[index].substitutes}
renderItem={({item,index})=>{
var i = index+1;
return (
<Detail
title={i}
value={item.player.name}
/>
);
}}
/>
</View>
): <Text>No data</Text>;
};
const styles = StyleSheet.create({
parent:{
borderRadius:8,
borderColor:Colors.black,
borderWidth:1,
backgroundColor:Colors.white,
marginHorizontal:16
},
image:{
height:100,
width:100,
alignSelf: 'center',
marginTop:16
},name:{
fontSize:24,
color:Colors.black,
alignSelf:'center',
marginTop:16
},
flatlist:{
margin:16
}
});
export default TeamLineup;
I am trying to search items in a flatlist, whenever i type in the search bar it only take one letter and closes the keyboard and the value inside the search bar disappear,
example when i type "george" it only takes the letter g and re-render a list of names containing the letter g and delete what's inside the search bar
how can i fix this ?
import React, { useState, useEffect } from 'react';
import { ScrollView } from 'react-native';
import { View, Text, FlatList, ActivityIndicator, SafeAreaView, TouchableOpacity } from 'react-native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { Divider, SearchBar } from 'react-native-elements'
const Item = ({ name, lastName }) => (
<View>
<Text style={{ fontSize: 17, color: '#666', marginBottom: 10 }}>Full name: {name} {lastName}</Text>
</View>);
function Clients({ navigation }) {
const [isLoading, setLoading] = useState(true);
const usersApi = 'https://reqres.in/api/users'
const [users, setUsers] = useState([]);
const [search, setSearch] = useState("");
const [masterData, setMasterData] = useState("");
const fetchJson = async (userApi) => {
const response = await fetch(userApi);
return response.json()
}
useEffect(() => {
fetchJson(usersApi)
.then((users) => {
setUsers(users.data);
setMasterData(users.data);
})
.catch((error) => (alert(error)))
.finally(() => setLoading(false));
}, []);
const itemSeparator = () => {
return (
<Divider style={{ width: "105%", marginVertical: 3, alignSelf: 'center' }} />
)
}
const renderHeader = () => {
return (
<SearchBar
placeholder="Type Here..."
lightTheme
round
onChangeText={text => searchFilterFunction(text)}
autoCorrect={false}
/>
);
};
const searchFilterFunction = text => {
setSearch(text);
const newData = masterData.filter(item => {
const itemData = `${item.first_name.toUpperCase()} ${item.last_name.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setUsers(newData);
};
const renderItem = ({ item }) => (
<TouchableOpacity style={{
flex: 1,
padding: 10
}}
onPress={() => { navigation.navigate('Client', { item: item }); }}
underlayColor='#ccc'
activeOpacity={0.1} >
<Item name={item.first_name} lastName={item.last_name} />
</TouchableOpacity>
);
console.log(search)
console.log(users)
return (
<SafeAreaProvider>
<SafeAreaView>
<Text style={{ color: '#666', margin: 15, fontSize: 20 }}>Clients actuels</Text>
<View style={{
width: '96%',
backgroundColor: 'white',
borderRadius: 5,
alignSelf: 'center',
marginTop: 20,
}}>
<View style={{ margin: 15 }}>
{isLoading ? <ActivityIndicator size="large" /> :
<FlatList
data={users}
renderItem={renderItem}
ItemSeparatorComponent={itemSeparator}
ListHeaderComponent={renderHeader}
keyExtractor={item => item.id.toString()}
value={search}
/>}
</View>
</View>
</SafeAreaView>
</SafeAreaProvider>
);
}
export default Clients;
I've had a problem when i used useState(). i have to filter by searched words on my data and list.
i need to define my data list with State (i'd list with searched words) but when i use State, i've taken 'Invalid Hook' error.
let [list, setList] = useState(data);
//called
data={list}
I don't find where i use that , I couldn't fix for 3 days, i can't reach next step :( I hope i'll fix with expert helps...
import React, {Component, useState} from 'react'
import {
Text,
StyleSheet,
View,
FlatList,
SafeAreaView,
ScrollView,
Image,
TextInput,
} from 'react-native'
import data from '../../data'
export default class Flatlistexample extends Component {
render () {
//defined below
let [list, setList] = useState(data);
seachFilter=(text)=>{
const newData = data.filter(item=>{
const listitem= `${item.name.toLowerCase()} ${item.company.toLowerCase()}`;
return listitem.indexOf(text.toLowerCase())
})
};
return (
<SafeAreaView
style={{
flex: 1,
}}>
<FlatList
//called
data={list}
renderItem={({item, index})=>{
return (
<ScrollView>
<SafeAreaView
style={[
styles.container,
{backgroundColor: index % 2 === 0 ? '#fafafa' : '#bbb'},
]}>
<Image style={styles.profile} source={{uri: item.picture}} />
<View style={styles.rightside}>
<Text style={styles.name}>{item.name}</Text>
<Text style={styles.company}>{item.company}</Text>
</View>
</SafeAreaView>
</ScrollView>
)
}}
keyExtractor={item => item._id}
ListHeaderComponent={() => {
const [search, setSearch] = useState('');
return (
<View style={styles.seachContainer}>
<TextInput
style={styles.textInput}
placeholder={'Search...'}
value={search}
onChangeText={text=>{
setSearch(text)
}}
></TextInput>
</View>
)
}}
/>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
borderBottomWidth: 1,
borderColor: 'gray',
},
profile: {
width: 50,
height: 50,
borderRadius: 25,
marginLeft: 10,
},
rightside: {
marginLeft: 20,
justifyContent: 'space-between',
marginVertical: 5,
},
name: {
fontSize: 22,
marginBottom: 10,
},
searchContainer: {
padding: 10,
borderWidth: 2,
borderColor: 'gray',
},
textInput: {
fontSize: 16,
backgroundColor: '#f9f9f9',
padding: 10,
},
})
Thank you
React hooks can be used with functional component only, here you are using class component
You need to understand the difference between functional component and class component first.
Here you are using class component so your state should be manageed in the following way
export default class Flatlistexample extends Component {
constructor(props)
{
this.state={list:[]}
}
}
and to update list
this.setState({list: <array of data>})
If you want to use hooks, your component needs to be changed something like the following:
const Flatlistexample = () => {
//defined below
let [list, setList] = useState(data);
seachFilter = (text) => {
const newData = data.filter(item => {
const listitem = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`;
return listitem.indexOf(text.toLowerCase())
})
};
return (
<SafeAreaView
style={{
flex: 1,
}}>
<FlatList data={list} renderItem={Your flatlist Item}/>
</SafeAreaView>
)
}
export default Flatlistexample
Here you go, I've added lots of comments. I hope you find this instructive. Let me know if you have questions!
import React, { useMemo, useState } from 'react'
import {
Text,
StyleSheet,
View,
FlatList,
SafeAreaView,
ScrollView,
Image,
TextInput,
} from 'react-native'
import data from '../../data'
// changed this to a functional component so you can use hooks. You can't use hooks in class components.
const Flatlistexample = () => {
// you don't actually need to `useState` for your list, since you're always just filtering `data`
// you would need to use `useState` if you were receiving data from an API request, but here it's static
const [search, setSearch] = useState('') // this should live in the main component so you can filter the list
const parsedSearch = search.toLowerCase() // do this once outside the filter, otherwise you're converting it for each item in the data array
const filteredList = useMemo(
() =>
data.filter(item => {
const itemText = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`
return itemText.indexOf(parsedSearch) > -1 // returns `true` if search is found in string
}),
[parsedSearch], // this will only run if parsedSearch changes
)
return (
<SafeAreaView style={{ flex: 1 }}>
<FlatList
//called
data={filteredList} // use the filtered list here
renderItem={({ item, index }) => {
return (
<ScrollView>
<SafeAreaView
style={[
styles.container,
{ backgroundColor: index % 2 === 0 ? '#fafafa' : '#bbb' },
]}
>
<Image style={styles.profile} source={{ uri: item.picture }} />
<View style={styles.rightside}>
<Text style={styles.name}>{item.name}</Text>
<Text style={styles.company}>{item.company}</Text>
</View>
</SafeAreaView>
</ScrollView>
)
}}
keyExtractor={item => item._id}
ListHeaderComponent={() => {
return (
<View style={styles.seachContainer}>
<TextInput
style={styles.textInput}
placeholder={'Search...'}
value={search}
onChangeText={text => {
setSearch(text)
}}
/>
</View>
)
}}
/>
</SafeAreaView>
)
}
export default Flatlistexample