Best practice to be DRY in terms of style in React Native with components such as TextInput? - react-native

I am using TextInput in multiple scenes to render "form" elements. They all share the same style, so what is good practice in React Native in terms of styling? I mean, I could define a style for the TextInput in every single component scene, but is there a way to be more DRY?

Wrap your TextInput in your own component. Add styles to it, and define props that you use a lot with that component. You can also pass other props (not explicitly defined) for example by using const { label, value, placeholder, onChange, multiline, onSubmit, ...passProps } = this.props; and then <TextInput label={label} ... {...passProps} />.

Related

Why useNavigation hook doesn't work in custom side bar?

If I create custom drawer:
<DrawerStack.Navigator
drawerContent={props => <SideMenu {...props} />}>
It requires to pass props in order to get navigation object inside it.
And if I have following:
<ClientsStack.Navigator>
<ClientsStack.Screen name="Clients" component={ClientsScreen} />
<ClientsStack.Screen
name="ClientDetails"
component={ClientDetailsScreen}
/>
</ClientsStack.Navigator>
And inside ClientsScreen I have FlatList which has:
renderItem={({ item }) => <ClientCard id={item.id} />}
inside ClientCard component which is not screen it's just dummy component
I can use useNavigation hook there.
Why it can be used there but not in custom drawer component?
You can't use useNavigation inside your drawerContent cause the hook is only available from your screens and their childs.
At the origin the only way to get navigation was to pass it from your screen to their childs. But since the useContext hook exist, the library provides a useNavigation to easily get the navigation in deep nested components. (and simplify the code a lot)
A drawer custom component is not a screen or wrapped into a screen. So there is just no reason to get the navigation from it with useNavigation. And I easily guess there is no usecase where we have deep nested components inside it cause it is usually just a menu.

Change SVG component on press with React Native

Background
Pretty simple question: I want to create a "like" button in RN. To do this I have to separate components which are SVG files. One is just the outline of a heart, the other one is filled.
The screen in which I'm trying to build this button is a Function component so I should use hooks. I know about state but don't know how to properly use it.
What I need
A Touchable Opacity component which holds an onPress method which changes the image component when pressed.
Thanks a lot in advance!
import React ,{useState} from 'react';
import {TouchableOpacity } from "react-native";
export default function Like() {
const [isLiked,setIsLiked]=useState(false) ;
const handleLikePress=()=>{
setIsLiked(!isLiked)
}
return (
<TouchableOpacity onPress={handleLikePress}>
{isLiked? <FilledHeartSVG/>: <OutlineHeartSVG/> }
</TouchableOpacity>
)
}
by default, we are showing an outline of a heart SVG
when press event trigger we are changing isLiked state value
if isLiked is true then show filled heart SVG
if isLiked is false then show outline of a heart SVG
FilledHeartSVG and OutlineHeartSVG is just example use your SVG there
You can do something like below, here i have made a toggle for the text but you can change it to your image component, also the callback prop can be used if you want to use that outside the LikeButton
const LikeButton = ({callback}) => {
const [liked, setLiked] = React.useState(false);
return (
<TouchableOpacity onPress={()=>{
setLiked(!liked);
if(callback)
{
callback();
}
}}>
<Text>{liked?"Liked":"Like"}</Text>
</TouchableOpacity>
);
};
You can tryout this snack which uses icons
https://snack.expo.io/#guruparan/likebutton

Styling multiple style props with styled-components on React Native

I have been using Styled-components with React web for a while now, but recently I have started working on a React Native app which I decided to use styled-compoents in. It's been great when styling components that have just the style property, such as the default react-native components.
The problem I've been having though is when I need to style a more complex component that has multiple style properties such as containerStyle, inputStyle, and others.
When it's only one style property with a different name I can do the following:
const StyledBadge = styled(({ style, ...rest }) => {
return <Badge {...rest} containerStyle={style} />;
})`
position: absolute;
right: 0;
top: 0;
`;
This works flawlessly but when the component has multiple styles, I have no idea what to do:
const StyledList = styled(({ style, ...rest }) => {
return <List {...rest} containerStyle={style} searchInputStyle={?} searchItemStyle={?} />;
})`
`;
With components like Gifted-React-Native-Chat is even worse because it has properties for passing properties as objects to its internal components, such as messageProps, listViewProps, containerProps and all of them have the style property.
Does anyone have any idea how to do that or if it's even possible?
I've been searching and trying to find a solution for this for a few days but I can't.
Thanks!
Here's how we ended up doing it.
Styled-components only work with the style prop but many custom components don't expose this prop. Instead they provide a *Style prop that gets passed to child component style props.
As an example, react-native-material-textfield has 5 style props.
We use the attrs function to keep the organization of styles in one file with the rest of the styled components.
This doesn't allow you to use traditional css syntax for the pseudo component, but it's the best we could think of to keep all styles organized.

Theming NativeBase Components for React Native

I see there's a way to theme (customize) NativeBase components for React Native: http://nativebase.io/docs/v0.5.0/customize
But I would like to customize an attribute of a particular component that is not part of the provided theme attributes. How would I customize the font size of the tab label for the Tabs component?
For a single component, you can use inline style attribute like this
<Button style={{backgroundColor: '#384850'}}>
Hello world
</Button>
If you want all the buttons to have this property then you can create a wrapping component like this
class MyButton extends React.Component {
render() {
return <Button style={backgroundColor: '#384850'}}>
{this.props.children}
</Button>;
}
}
and then you can use
<MyButton>
Hello world
</MyButton>

Is there a way in which I can ignore touch events on Text in React Native?

I want to implement floating labels, for this I have a Text Component Above a TextInput. I want to ignore all the touch events on the Text so that the TextInput under it gets all the events. Is there a way I can do this ? In CSS we used to have pointer-events: none, I am not sure how to do this in React Native.
In react-native, pointerEvents is a prop, not a style.
<View pointerEvents="none" />
Add pointerEvents: 'none' to the Text component. This allows touch events to go to the ancestors of the component, but not the component itself or its children.
React Native also supports 'box-none', which allows touch events to go to the ancestors and children of the component, and excludes only the component itself.
I had the same problem as Cryszon. On Android is seems like pointerEvents="none" doesn't work for Text components.
Wrapping the Text in a View and putting the pointerEvents="none" prop there solved it.
pointerEvents work only on View not on Text or TouchableOpacity.
If you have an issue where even 'box-none' doesn't allow touch events to go to the children, you could do something like this
let setPointerEvents = 'none';
...
<View pointerEvents={setPointerEvents}>
...
<TouchableOpacity onPress= {()=>this.set(false)}/>
</View>
<TouchableOpacity onPress= {()=>this.set(true)}/>
...
set(bool){
switch(bool){
case true:
setPointerEvents= 'auto'
break;
case false:
setPointerEvents= 'none'
break;
}
}
Kind of a hack, but it works.