1. Scenario
Let’s imagine that you need to implement a list of names using TypeScript + Styled Components, like the image below:
2. Dependencies
If you haven’t installed styled-components yet, open your terminal inside your typescript React Native project, copy and paste the lines below:
yarn add styled-components
yarn add @types/styled-components -D
3. Implementing without Styled Components
I am going to implement the list without styled-components, so we can change one part per time.
First, I will define the interface of the objects that are going to be in the list and the data of the items that are going to be rendered
export interface IUser {
id: string;
name: string;
}
const DATA = [
{
id: '1',
name: 'Michael Scott',
},
{
id: '2',
name: 'Jim Halpert',
},
{
id: '3',
name: 'Pam Beesly',
},
{
id: '4',
name: 'Dwight Schrute',
},
{
id: '5',
name: 'Andy Bernard',
},
{
id: '6',
name: 'Ryan Howard',
},
{
id: '7',
name: 'Kelly Kapoor',
},
{
id: '8',
name: 'Toby Flenderson',
},
{
id: '9',
name: 'Stanley Hudson',
},
{
id: '10',
name: 'Phyllis Vance',
},
];
Now I’m going to create the Component that will render each IUser item on the list.
const Item = ({data}: {data: IUser}) => (
<View
style={{
backgroundColor: '#eeeeee',
borderRadius: 10,
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
}}>
<Text style={{fontSize: 24}}>{data.name}</Text>
</View>
);
The first important part here is that you should destruct the data prop that we’re passing to the Item component and type it with the IUser interface.
Finally, I will create the Flatlist component:
const App = () => {
return (
<View style={{flex: 1}}>
<FlatList
data={DATA}
renderItem={({item}) => <Item data={item} />}
keyExtractor={(item: IUser) => item.id}
/>
</View>
);
};
4. Adding Styled Components
Now, we are ready to refactor these components using styled-components.
First, I will create a file and name it styles.ts
Now, I will create a style for each component that we created previously.
import {FlatList} from 'react-native';
import styled from 'styled-components/native';
import {IUser} from './App';
export const Container = styled.View`
flex: 1;
`;
export const ItemContainer = styled.View`
background-color: #eeeeee;
border-radius: 10px;
padding: 20px;
margin-vertical: 8px;
margin-horizontal: 16px;
`;
export const ItemName = styled.Text`
font-size: 24px;
`;
export const UsersList = styled.FlatList`
padding: 20px;
`;
After that, we can replace the components with inline styles with the isolated styles that we just created.
const Item = ({data}: {data: IUser}) => (
<ItemContainer>
<ItemName>{data.name}</ItemName>
</ItemContainer>
);
const App = () => {
const renderItem: ListRenderItem<IUser> = ({item}) => <Item data={item} />;
return (
<Container>
<UsersList
data={DATA}
renderItem={renderItem}
keyExtractor={(item: IUser) => item.id}
/>
</Container>
);
};
But you will see that Typescript will fire an error in your styled-Component created Flatlist
That’s because you have to declare the type of data that we’re passing to the Flatlist to the styled-component flatlist.
So go to your styles.ts file and change the UsersList style from:
export const UsersList = styled.FlatList`
padding: 20px;
`;
To:
export const UsersList = styled(FlatList as new () => FlatList<IUser>)`
padding: 20px;
`;
5. Conclusion and Final Result
Using TypeScript + Flatlists + Styled Components can be tricky sometimes, but I hope that this tutorial helps you somehow.
That’s our final App.tsx file:
import React from 'react';
import {ListRenderItem} from 'react-native';
import {Container, ItemContainer, ItemName, UsersList} from './styles';
export interface IUser {
id: string;
name: string;
}
const DATA = [
{
id: '1',
name: 'Michael Scott',
},
{
id: '2',
name: 'Jim Halpert',
},
{
id: '3',
name: 'Pam Beesly',
},
{
id: '4',
name: 'Dwight Schrute',
},
{
id: '5',
name: 'Andy Bernard',
},
{
id: '6',
name: 'Ryan Howard',
},
{
id: '7',
name: 'Kelly Kapoor',
},
{
id: '8',
name: 'Toby Flenderson',
},
{
id: '9',
name: 'Stanley Hudson',
},
{
id: '10',
name: 'Phyllis Vance',
},
];
const Item = ({data}: {data: IUser}) => (
<ItemContainer>
<ItemName>{data.name}</ItemName>
</ItemContainer>
);
const App = () => {
const renderItem: ListRenderItem<IUser> = ({item}) => <Item data={item} />;
return (
<Container>
<UsersList
data={DATA}
renderItem={renderItem}
keyExtractor={(item: IUser) => item.id}
/>
</Container>
);
};
export default App;
And that’s our final styles.ts file:
import {FlatList} from 'react-native';
import styled from 'styled-components/native';
import {IUser} from './App';
export const Container = styled.SafeAreaView`
flex: 1;
`;
export const ItemContainer = styled.View`
background-color: #eeeeee;
border-radius: 10px;
padding: 20px;
margin-vertical: 8px;
margin-horizontal: 16px;
`;
export const ItemName = styled.Text`
font-size: 24px;
`;
export const UsersList = styled(FlatList as new () => FlatList<IUser>)`
padding: 20px;
`;
And here’s the tutorial repository on GitHub.
Top comments (5)
Yea man! Thanks, this worked for me. Btw, I had some difficulty passing extra props to the components inside the renderItem function, maybe cause I'm a newbie or a stupid idiot (lol), but for those who have the same difficulty here is the solution:
Using the same example code, let's suppose we want a "selected" prop that based on its state value we give a different style to the list item container. We have to pass the "selected" prop to the renderItem function, but the Item component does not expect to receive this prop, so we must indicate to the component that it can receive a "selected" prop like this:
At this point we can retrieve the value of the prop in the styles, but the styled-component "ItemContainer" also doesn't expect to receive a selected property, so we must create an interface with the props it should expect and pass it as generic to the component, like this:
I know it can be simple but I hope it helps someone starting with React Native like me. And sorry if this is not the best way, but it was the solution I found. And don't forget to implement the logic for change the selected item lol
Thanks!
For me, what seemed to work fine in styled component , was something like
Very well explained. Thanks for sharing this Everaldo! 🙂