How do I make a wrapper component to style a picker item in react-native-picker? - react-native

I'm using react-native-community/picker v1.6.1, and I'm trying to make a pre-styled picker item to avoid having the color property on each item. Below is a showcase App.js. The red picker works as expected but the yellow one renders in black instead of yellow and I don't understand why. The code is tested in an iOS emulator with a freshly generated React Native app version 0.62.2 where I've installed the picker component.
import React, {useState} from 'react';
import {SafeAreaView} from 'react-native';
import {Picker} from '#react-native-community/picker';
const YellowPickerItem = props => {
return <Picker.Item {...props} color={'yellow'} />;
};
const App = () => {
const [redValue, setRedValue] = useState(2);
const [yellowValue, setYellowValue] = useState(3);
return (
<>
<SafeAreaView style={{flex: 1}} backgroundColor={'gray'}>
<Picker selectedValue={redValue} onValueChange={setRedValue}>
<Picker.Item label={'Red 1'} value={1} key={1} color={'red'} />
<Picker.Item label={'Red 2'} value={2} key={2} color={'red'} />
<Picker.Item label={'Red 3'} value={3} key={3} color={'red'} />
<Picker.Item label={'Red 4'} value={4} key={4} color={'red'} />
</Picker>
<Picker selectedValue={yellowValue} onValueChange={setYellowValue}>
<YellowPickerItem label={'Yellow 1'} value={1} key={1} />
<YellowPickerItem label={'Yellow 2'} value={2} key={2} />
<YellowPickerItem label={'Yellow 3'} value={3} key={3} />
<YellowPickerItem label={'Yellow 4'} value={4} key={4} />
</Picker>
</SafeAreaView>
</>
);
};
export default App;
The strangest thing is that the code runs just as well if I change the YellowPickerItem component to:
const YellowPickerItem = props => {
return <SafeAreaView />;
};
It feels like I'm missing something basic about react components here, so grateful for a nudge in the right direction.
Markus

You can use itemStyle prop of the picker to styling your picker item.

Related

React Native - VirtualizedLists should never be nested inside plain ScrollViews with the same orientation

I'm working on an app for existing web application with expo cli.
I have completed the home screen but I'm getting this warning when using ScrollView
VirtualizedLists should never be nested inside plain ScrollViews with
the same orientation - use another VirtualizedList-backed container
instead.
I have a folder screens where I've all the pages of the website. so currently I have Home.js where I have different sections.
<View>
<Showcase />
<StepsList />
<HomeInfo />
<HomeCorporateMenu />
<HomeMonthlyMenus />
</View>
Then rendeing this component in the root component App.js. but I was not able to scroll down to see other sections.
So I've added SafeAreaView and ScrollView components. now I'm able to scroll but sometimes I get that warning in the console.
I have looked it up SO and found some solutions.
Added style={{ flex: 1 }} and keyboardShouldPersistTaps='always' to ScrollView component
But Still getting the same warning. Any suggestions?
<SafeAreaView style={styles.container}>
<ScrollView>
<Header />
<HomeScreen />
</ScrollView>
</SafeAreaView>
The warning is, obviously, telling you that you shouldn't nest multiple VirtualizedList (FlatList and SectionList) components with the same orientation (the orientation of your lists is probably vertical).
To do it properly, and for the warning to disappear, you have to use the ListHeaderComponent or ListFooterComponent prop of the VirtualizedList and nest them like this:
const App = () => {
const ListFooterComponent = (
<>
<FlatList
// other FlatList props
data={stepsListData}
/>
<FlatList
// other FlatList props
data={homeInfoData}
/>
<FlatList
// other FlatList props
data={homeCorporateMenuData}
/>
{/* ... */}
</>
);
return (
<FlatList
// other FlatList props
data={showcaseData}
ListFooterComponent={ListFooterComponent}
/>
);
};
Or another possible workaround (and not an official resolution) would be to use a FlatList with empty data and renderItem props instead of using a ScrollView. Instead of this:
const App = () => {
return (
<SafeAreaView style={styles.container}>
<ScrollView>
<Header />
<HomeScreen />
</ScrollView>
</SafeAreaView>
);
};
You can use this:
const emptyData = [];
const renderNullItem = () => null;
const App = () => {
const ListFooterComponent = (
<>
<Header />
<HomeScreen />
</>
);
return (
<SafeAreaView style={styles.container}>
<FlatList
data={emptyData}
renderItem={renderNullItem}
ListFooterComponent={ListFooterComponent}
/>
</SafeAreaView>
);
};

One form, but different state

I'm moving now from other technologies to React Native and I have a problem. I have one presentational component which is <TaskInput />.
const TaskInput = (props: ITaskInputProps) => {
return (
<View style={styles.container} >
<Text style={styles.title}>{props.title}</Text>
<TextInput
style={styles.input}
multiline
scrollEnabled={false}
/>
</View>
)
}
ParentComponent over TaskInput
import React from 'react';
import { View } from 'react-native';
import styles from './styles';
import TaskInputContainer from '../task-input';
interface ITaskConfigurationProps {
title: string,
isInputForm?: boolean,
isRequired?: boolean,
}
const TaskConfiguration = (props: ITaskConfigurationProps) => {
return (
<View style={(props.isRequired) ? [styles.container, {backgroundColor: '#f25e5e'}] : styles.container}>
{ props.isInputForm && <TaskInputContainer title={props.title} /> }
</View>
);
}
export default TaskConfiguration;
const TaskScreen = (props: ITaskScreenProps) => {
return (
<View style={styles.container}>
<SectionTitle title={'Task Settings'} />
<ScrollView contentContainerStyle={styles.configurations}>
<TaskConfiguration title={"What you need to do?"} isInputForm={true} isRequired={true} />
<TaskConfiguration title={"Description"} isInputForm={true} />
<TaskConfiguration title={"Deadline"} />
<TaskConfiguration title={"Priority"} />
</ScrollView>
<Button isDone={true} navigation={props.navigation} />
</View>
)
}
TaskInput component takes one prop which is title and it will be in two places on my screen. One component will be called "Enter main task", another one is "Description". But this component will accept different states like currentMainTextInput and currentDescriptionTextInput. This is my idea of re-usable component TextInput, but I can't do what I want because if I set type in one input - other input will re-render with first input (both of them are one presentational component).
I want to use this dumb component in any place of my app. I don't want to create a new identical component and duplicate code, How can I do that? (P.S. I was thinking about "redux or class/hooks", but what should I use...)

React Native - trigger scrolling of FlatList outside the FlatList

I have a vertical FlatList component and two buttons as TouchableOpacity, how do I perform scrolling of the FlatList with the buttons,
i.e. 'scrolling the FlatList towards bottom` and 'scroll the FlatList towards top'?
Minimal Example:
<View>
<FlatList/>
<TouchableOpacity>
<Text>Scroll towards Top</>Text
</TouchableOpacity>
<TouchableOpacity>
<Text>Scroll towards Bottom</>Text
</TouchableOpacity>
</View>
This is not difficult to accomplish, The <Flatlist/> component already have methods to do that.
scrollToEnd(): Scrolls to the end of the content.
scrollToIndex(): Scrolls to the item at the specified index such 0 which is the top.
I have created a simple demo for you: https://snack.expo.io/#abranhe/flatlist-scroll
I have created a custom <Button/> and <Card/> components. I am creating an array with some random data with this format
const data = [
{ message: 'Random Message' }, { message: 'Random Message' }
]
I am adding a reference to the <Flatlist/> by adding
ref={ref => (this.flatlist = ref)}
Then I call the methods and that's it.
<Button title="▼" onPress={() => this.flatlist.scrollToEnd()} />
The whole source code:
import React from 'react';
import { Text, View, FlatList, StyleSheet } from 'react-native';
import { random } from 'merry-christmas';
import Card from './components/Card';
import Button from './components/Button';
const data = [...Array(10)].map(i => ({ message: random() }));
export default () => (
<View style={styles.container}>
<FlatList
ref={ref => (this.flatlist = ref)}
data={data}
renderItem={({ item }) => <Card gretting={item.message} />}
/>
<View style={styles.bottomContainer}>
<Button
title="▲"
onPress={() => this.flatlist.scrollToIndex({ index: 0 })}
/>
<Button title="▼" onPress={() => this.flatlist.scrollToEnd()} />
</View>
</View>
);
You can use a scrollView component

selectedSearchTab is not a function

Working with react-native is mega frustrating. Its more frustrating because I am new to it. I have written component that takes redux action as an input.
import React from "react";
import {Text} from "react-native";
import styles from "./searchBoxStyles";
import {View,InputGroup,Input} from "native-base";
import Icon from "react-native-vector-icons/FontAwesome";
export const SearchBox = (getInputData,selectedSearchTab) => {
function handleInput(key,val){
getInputData({
key,
value:val});
}
return(
<View style={styles.searchBox}>
<View style={styles.inputWrapper}>
<Text style={styles.label}>PickUp</Text>
<InputGroup>
<Icon name="search" size={15} color="#FF5E3A"/>
<Input onFocus={()=>selectedSearchTab("pickUp")} style={styles.inputSearch} placeholder="choose pickup location" onChanangeText={handleInput.bind(this,"pickUp")}/>
</InputGroup>
</View>
<View style={styles.secondInputWrapper}>
<Text style={styles.label}>DropOff</Text>
<InputGroup>
<Icon name="search" size={15} color="#FF5E3A"/>
<Input onFocus={()=>selectedSearchTab("dropOff")} style={styles.inputSearch} placeholder="choose drop off location" onChanangeText={handleInput.bind(this,"dropOff")}/>
</InputGroup>
</View>
</View>
);
};
export default SearchBox;
getInputData & selectedSearchTab are both redux actions, passed down from container component.
Clicking on the textBox I get selectedSearchTab is not a function error.

React native picker not showing on android

I'm trying to use the Picker component and it shows perfectly fine in iOS but nothing in Android. I've checked the comments on react native picker is not showing in android however setting the {width: 100} and {flex: 1} doesn't seem to solve the problem.
Update: The Picker is there, works when I tap on the area it's on, just not visible.
I'm using Expo to run the test builds on my iphone and android. No problem on iphone. Just android... Galaxy S8 v7.0 Nougat
Here's my code:
import React from 'react';
import {
StyleSheet,
Text,
View,
Picker,
} from 'react-native';
export default class Home extends React.Component {
constructor(props){
super(props);
this.state = {
selectedValue: 'Orange'
}
}
render() {
return (
<View style={styles.container}>
<Picker
style={styles.picker}
selectedValue={this.state.selectedValue}
onValueChange={(value) => {this.setState({selectedValue: value})}}
itemStyle={styles.pickerItem}
>
<Picker.Item label="Apple" value="Apple" />
<Picker.Item label="Orange" value="Orange" />
<Picker.Item label="Banana" value="Banana" />
<Picker.Item label="Kiwi" value="Kiwi" />
</Picker>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flexDirection: 'column',
justifyContent: 'center',
},
picker: {
flex: 1,
},
pickerItem: {
color: '#333333'
},
});
Try To add height and width for Picker. Try Following
<Picker
style={{height:30, width:100}}
selectedValue={this.state.selectedValue}
onValueChange={(value) => {this.setState({selectedValue: value})}}
itemStyle={styles.pickerItem}>
<Picker.Item label="Apple" value="Apple" />
<Picker.Item label="Orange" value="Orange" />
<Picker.Item label="Banana" value="Banana" />
<Picker.Item label="Kiwi" value="Kiwi" />
</Picker>
Found the problem, I exported the module and imported it in my main app.js file and in there I wrapped the module in a container with alignItems: 'center'. Apparently this causes the picker to not show. See this https://github.com/facebook/react-native/issues/6110
I had the same problem and the cause was that I had set alignItems: 'center' to the parent view. This is what I wanted though so I didn't remove it. Instead I solved it by giving the picker a width of 100%.
<View style={{alignItems: "center"}}>
<Picker style={{width:"100%"}} mode="dropdown">
<Picker.Item />
</Picker>
</View>