Hello everyone ππΌ
I am very excited to share some of the things that I have learned in my journey as a software engineer. For those who want to see the code of this tutorial => Here! For those who want to watch the video version => Here!
Creating the project
We are going to be using Expo for this project so the command to create our app would be something like this
Create a project named search-filter
$ expo init search-filter
Navigate to the project directory
$ cd search-filter
Installing dependencies
we are going to need basic navigation for our app, once you are in your project folder run the following commands.
$ yarn add @react-navigation/native
$ expo install react-native-screens react-native-safe-area-context
$ yarn add @react-navigation/native-stack
$ yarn add @react-navigation/bottom-tabs
Once the dependencies are installed we can go ahead and start de development server
Start the development server
$ expo start
Navigation
Now we are going to set the navigation for our app We have a bottom tab with two screens, MyStack and Settings and we also have a component called MyStack which contains the Home and the Stack screen Here we have the code for the navigation.
import React from "react";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import { NavigationContainer } from "@react-navigation/native";
//screens
import HomeScreen from "./screens/HomeScreen";
import SettingsScreen from "./screens/SettingsScreen";
import StackScreen from "./screens/StackScreen";
import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
const HomeStackNavigator = createNativeStackNavigator();
function MyStack() {
return (
<HomeStackNavigator.Navigator initialRouteName="HomeScreen">
<HomeStackNavigator.Screen name="HomeScreen" component={HomeScreen} />
<HomeStackNavigator.Screen
name="Stack"
component={StackScreen}
options={{
headerBackTitleVisible: false,
}}
/>
</HomeStackNavigator.Navigator>
);
}
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator
initialRouteName="Home"
screenOptions={{
tabBarActiveTintColor: "purple",
}}
>
<Tab.Screen
name="Home"
component={MyStack}
options={{
tabBarLabel: "Feed",
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons name="home" color={color} size={30} />
),
tabBarBadge: 10,
headerShown: false,
}}
/>
<Tab.Screen
name="Settings"
component={SettingsScreen}
options={{
tabBarLabel: "Settings",
tabBarIcon: ({ color, size }) => (
<MaterialCommunityIcons
name="brightness-5"
color={color}
size={30}
/>
),
}}
/>
</Tab.Navigator>
);
}
export default function Navigation() {
return (
<NavigationContainer>
<MyTabs />
</NavigationContainer>
);
}
Note that we also need to create our screens files:
HomeScreen.js
SettingsScreen.js
StackScreen.js
For SettingsScreen
and StackScreen
we will just show a text as the following code.
import React from "react";
import { View, Text } from "react-native";
const SettingsScreen = () => {
return (
<View>
<Text
style={{
fontSize: 30,
textAlign: "center",
marginTop: "20%",
}}
>
Settings Screen
</Text>
</View>
);
};
export default SettingsScreen;
import React from "react";
import { View, Text } from "react-native";
const StackScreen = () => {
return (
<View>
<Text
style={{
fontSize: 30,
textAlign: "center",
marginTop: "20%",
}}
>
Stack Screen
</Text>
</View>
);
};
export default StackScreen;
Finally we can start working on our HomeScreen.js file, for now we can just show a text as well while we are working on getting the fake data from our API.
import React from "react";
import { View, Text } from "react-native";
const HomeScreen = () => {
return (
<View>
<Text
style={{
fontSize: 30,
textAlign: "center",
marginTop: "20%",
}}
>
HomeScreen Screen
</Text>
</View>
);
};
export default HomeScreen;
Getting fake data from Random user API
After we have our project running we can now get our fake data from our API.
We will need to import useEffect and useState from react, we create a variable called data
that is going to contain the fake users, then we simply use the built-in function βfetchβ
to get the data then we transform the response to a json file and finally, we set our data.
You can console.log the response to check what kind of data we got and play around with it.
import React, { useEffect, useState } from "react";
import { View, Text } from "react-native";
const HomeScreen = () => {
const [data, setData] = useState([]);
useEffect(() => {
fetchData("https://randomuser.me/api/?results=20");
}, []);
const fetchData = async (url) => {
try {
const response = await fetch(url);
const json = await response.json();
setData(json.results);
setFilteredData(json.results);
console.log(json.results);
} catch (error) {
console.error(error);
}
};
return (
<View>
<Text
style={{
fontSize: 30,
textAlign: "center",
marginTop: "20%",
}}
>
Home Screen
</Text>
</View>
);
};
export default HomeScreen;
Displaying the data
Now that we have our data, we need to show it on screen. We will map throw the data array and render a simple component that shows each user in our array.
return (
<ScrollView>
<Text style={styles.textFriends}>{data.length} Friends</Text>
{data.map((item, index) => {
return (
<View key={index} style={styles.itemContainer}>
<Image source={{ uri: item.picture.large }} style={styles.image} />
<View>
<Text style={styles.textName}>
{item.name.first} {item.name.last}
</Text>
<Text style={styles.textEmail}>{item.login.username}</Text>
</View>
</View>
);
})}
</ScrollView>
);
};
export default HomeScreen;
const styles = StyleSheet.create({
textFriends: {
fontSize: 20,
textAlign: "left",
marginLeft: 10,
fontWeight: "bold",
marginTop: 10,
},
itemContainer: {
flexDirection: "row",
alignItems: "center",
marginLeft: 10,
marginTop: 10,
},
image: {
width: 50,
height: 50,
borderRadius: 25,
},
textName: {
fontSize: 17,
marginLeft: 10,
fontWeight: "600",
},
textEmail: {
fontSize: 14,
marginLeft: 10,
color: "grey",
},
});
Adding the search bar and filtering data. Finally! π
- First, we need to import
useNavigation
- Using another useEffect we will set the header options for HomeScreen
- We also need another variable to hold the filtered data
- Finally, we create a function called
searchFilterFunction()
that will check if we have text in the search bar, if we have text then we will pass that text to uppercase and since we are filtering the data by name we also pass the name to uppercase. Then we simply return the filtered data using the methodindexOf()
which returns the first index at which a given element (text) can be found in the array, or -1 if it is not present.
After we add that our code should look like this.
import React, { useEffect, useState } from "react";
import {
View,
Text,
StyleSheet,
TouchableOpacity,
ScrollView,
Image,
} from "react-native";
import { useNavigation } from "@react-navigation/native";
const HomeScreen = () => {
const navigation = useNavigation();
const [data, setData] = useState([]);
const [filteredData, setFilteredData] = useState([]);
useEffect(() => {
fetchData("https://randomuser.me/api/?results=30");
}, []);
useEffect(() => {
navigation.setOptions({
headerLargeTitle: true,
headerTitle: "Home",
headerRight: () => (
<TouchableOpacity
onPress={() => navigation.navigate("Stack")}
style={{
backgroundColor: "purple",
width: 30,
height: 30,
borderRadius: 10,
justifyContent: "center",
}}
>
<Text
style={{
fontSize: 20,
textAlign: "center",
color: "white",
}}
>
+
</Text>
</TouchableOpacity>
),
headerSearchBarOptions: {
placeholder: "Friends",
onChangeText: (event) => {
searchFilterFunction(event.nativeEvent.text);
},
},
});
}, [navigation]);
const fetchData = async (url) => {
try {
const response = await fetch(url);
const json = await response.json();
setData(json.results);
setFilteredData(json.results);
console.log(json.results);
} catch (error) {
console.error(error);
}
};
const searchFilterFunction = (text) => {
if (text) {
const newData = data.filter((item) => {
const itemData = item.name.first
? item.name.first.toUpperCase()
: "".toUpperCase();
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setFilteredData(newData);
} else {
setFilteredData(data);
}
};
return (
<ScrollView>
<Text style={styles.textFriends}>{filteredData.length} Friends</Text>
{filteredData.map((item, index) => {
return (
<View key={index} style={styles.itemContainer}>
<Image source={{ uri: item.picture.large }} style={styles.image} />
<View>
<Text style={styles.textName}>
{item.name.first} {item.name.last}
</Text>
<Text style={styles.textEmail}>{item.login.username}</Text>
</View>
</View>
);
})}
</ScrollView>
);
};
export default HomeScreen;
const styles = StyleSheet.create({
textFriends: {
fontSize: 20,
textAlign: "left",
marginLeft: 10,
fontWeight: "bold",
marginTop: 10,
},
itemContainer: {
flexDirection: "row",
alignItems: "center",
marginLeft: 10,
marginTop: 10,
},
image: {
width: 50,
height: 50,
borderRadius: 25,
},
textName: {
fontSize: 17,
marginLeft: 10,
fontWeight: "600",
},
textEmail: {
fontSize: 14,
marginLeft: 10,
color: "grey",
},
});
Conclusion
That is all it takes to create that useful functionality. Happy Coding!