I have a screen with a button upon pressing which, a new view with a picker will be rendered. How do I set selectedValue for these pickers, if they all should be independent from each other?
I tried using an array and passing indices as an argument to the view generating function, but that doesn't seem to work.
import React from "react";
import { View, Picker, Button } from "react-native";
export default class SessionScreen extends React.Component {
state = {
externalData: ["Player1", "Player2", "Player3", "Player4"],
view: [],
selectedPlayers: []
};
async view(index) {
let players = this.state.externalData.map((s, i) => {
return <Picker.Item key={i} value={s} label={s} />;
});
let newVal = (
<View
key={this.state.selectedPlayers[index] + "view" + index}
style={{ flex: 1, flexDirection: "column", paddingTop: 60 }}
>
<View style={{ flexDirection: "row" }}>
<Picker
key={this.state.selectedPlayers[index] + "picker" + index}
selectedValue={this.state.selectedPlayers[index - 1]}
style={{ height: 50, width: 200 }}
onValueChange={itemValue =>
this.setState(prevState => ({
selectedPlayers: [...prevState.selectedPlayers, itemValue]
}))
}
>
{players}
</Picker>
</View>
</View>
);
await this.setState(prevState => ({
view: [...prevState.view, newVal]
}));
}
async addPlayer() {
await this.view(this.state.selectedPlayers.length);
}
render() {
var returnValue = [];
if (this.state.view.length > 0) returnValue = [...this.state.view];
returnValue.push(
<View
key={returnValue.length + 1}
style={{ flex: 1, flexDirection: "column", paddingTop: 100 }}
>
<Button
title="Add a player"
onPress={this.addPlayer.bind(this)}
accessibilityLabel="Add a new player to the table"
>
Add a player
</Button>
</View>
);
return returnValue;
}
}
When Add A Player button is pressed, a new Picker appears on the screen. When I pick a different value from the given items, it is still displaying 'Player1'. But when I press 'Add a Player' again, the value I had chosen in the first picker appears in the second one.
I am sure it's not the best approach to solving this problem and I am open to suggestions.
P.S. It's my third day trying to do something in react-native, or react at all.
Related
I am trying to make a game in react-native. I want to render 200+ views on the Game screen. Each View has a pressable functionality. Whenever I press the View I need to run a function that will change the View background color and update score on the game context. But Whenever I try to press any View it took some time to change the background and update the context.
Note
I am using the expo as a development environment and I am using a real device too.
My View Component
import { useEffect, useState, memo } from "react";
import { useContext } from "react";
import { gameContext } from "./gameContext";
import { Pressable, View } from "react-native";
function CheckBoxCom() {
const [active, setActive] = useState(false);
const { score, setScore } = useContext(gameContext);
useEffect(() => {
let time = setTimeout(() => {
setActive(false);
}, Math.floor(Math.random() * 35000));
return () => clearTimeout(time);
}, [active]);
const handlePress = () => {
if (active) return;
setActive(true);
setScore(score + 1);
};
return (
<View>
<Pressable onPress={handlePress}>
<View
style={{
width: 20,
height: 20,
borderWidth: 2,
borderColor: active ? "green" : "gray",
margin: 3,
borderRadius: 3,
backgroundColor: active ? "green" : null,
}}
></View>
</Pressable>
</View>
);
}
export default memo(CheckBoxCom);
Game Screen Component
import { useContext, useEffect, useState } from "react";
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View, FlatList } from "react-native";
import CheckBox from "./CheckBox";
import { gameContext } from "./gameContext";
export default function Game({ navigation }) {
const { score, time, setTime, boxList } = useContext(gameContext);
const [intervalId, setIntervalId] = useState("");
useEffect(() => {
const int = setInterval(() => {
setTime((prvTime) => prvTime - 1);
}, 1000);
setIntervalId(int);
return () => clearInterval(int);
}, []);
if (time === 0) {
clearInterval(intervalId);
navigation.navigate("Score", { score });
}
return (
<View style={{ flex: 1 }}>
<StatusBar style="auto" />
<View style={styles.textHeader}>
<Text>Score : {score}</Text>
<Text>Time Left: {time}s</Text>
</View>
<View style={styles.checkBoxContainer}>
<FlatList
style={{ alignSelf: "center" }}
data={boxList}
initialNumToRender={50}
numColumns={12}
renderItem={(i) => <CheckBox />}
keyExtractor={(i) => i.toString()}
scrollEnabled={false}
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
textHeader: {
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
width: "100%",
marginTop: 40,
paddingHorizontal: 30,
},
checkBoxContainer: {
margin: 20,
display: "flex",
flexWrap: "wrap",
height: "80%",
overflow: "hidden",
flexDirection: "row",
},
});
How can I run view function immediately whenever I press it?
The reason it is slow is that when you press on a view, all 200+ CheckBoxCom components rerender. If they don't need to, we can improve performance by trying to prevent those unnecessary rerenders.
I believe the major bottleneck here is the gameContext. It groups together a lot of states and if any of these were to change, all components will rerender. It provides score state that you are reading within each CheckBoxCom. Whenever the score changes all CheckBoxCom components will re-render. If you change handlePress() to:
const handlePress = () => {
if (active) return;
setActive(true);
setScore(score => score + 1);
};
Please note the use of callback to update the score in the above handler. In this case, we don't need to read score from context, so we can remove it from the game context provider, only pass setScore. Removing score from the context provider is important because not doing so will rerender all components using the context even if you don't specifically destructure score.
Also, make sure you don't have a lot of state variables within a single context. Split it into multiple contexts if you have different states in there. In this way, you will be able to reduce unnecessary rerenders of the CheckBoxCom components.
Since your CheckBoxCom components have an internal state, using React.memo() will not help to prevent rerenders because it only works for rerenders resulting from changed props.
But if you are able to refactor them to lift the active state up to the parent i.e. something like activeViews or something (which could be a map of indexes which are true i.e. active), then you can pass the active state as a boolean prop to each CheckBoxCom component. And if we also pass setScore via a prop instead of via context, we can benefit from React.memo(). BTW it is not necessary to wrap setState methods with useCallback().
The end result will be: CheckBoxCom components with zero internal states and no reliance on context, in other words, pure components i.e. components which work nicely with React.memo().
Use pagination in flatlist
for ref: Pagination in flatlist
import React, { Component } from 'react';
import {
View,
Text,
TouchableOpacity,
StyleSheet,
FlatList,
Platform,
ActivityIndicator,
} from 'react-native';
export default class App extends Component {
constructor() {
super();
this.state = {
loading: true,
//Loading state used while loading the data for the first time
serverData: [],
//Data Source for the FlatList
fetching_from_server: false,
//Loading state used while loading more data
};
this.offset = 0;
//Index of the offset to load from web API
}
componentDidMount() {
//fetch('http://aboutreact.com/demo/getpost.php?offset=' + this.offset)
fetch('https://www.doviz.com/api/v1/currencies/all/latest')
.then(response => response.json())
.then(responseJson => {
responseJson = responseJson.slice((this.offset*12),((this.offset+1)*12)-1)
console.log("offset : "+this.offset);
console.log(responseJson.slice((this.offset*12),((this.offset+1)*12)-1));
//Successful response from the API Call
this.offset = this.offset + 1;
//After the response increasing the offset for the next API call.
this.setState({
// serverData: [...this.state.serverData, ...responseJson.results],
serverData: [...this.state.serverData, ...responseJson],
//adding the new data with old one available in Data Source of the List
loading: false,
//updating the loading state to false
});
})
.catch(error => {
console.error(error);
});
}
loadMoreData = () => {
//On click of Load More button We will call the web API again
this.setState({ fetching_from_server: true }, () => {
//fetch('http://aboutreact.com/demo/getpost.php?offset=' + this.offset)
fetch('https://www.doviz.com/api/v1/currencies/all/latest')
.then(response => response.json())
.then(responseJson => {
responseJson = responseJson.slice((this.offset*12),((this.offset+1)*12)-1)
console.log("offset Load : "+this.offset);
console.log(responseJson);
//Successful response from the API Call
this.offset = this.offset + 1;
//After the response increasing the offset for the next API call.
this.setState({
//serverData: [...this.state.serverData, ...responseJson.results],
serverData: [...this.state.serverData, ...responseJson],
fetching_from_server: false,
//updating the loading state to false
});
})
.catch(error => {
console.error(error);
});
});
};
renderFooter() {
return (
//Footer View with Load More button
<View style={styles.footer}>
<TouchableOpacity
activeOpacity={0.9}
onPress={this.loadMoreData}
//On Click of button calling loadMoreData function to load more data
style={styles.loadMoreBtn}>
<Text style={styles.btnText}>Loading</Text>
{this.state.fetching_from_server ? (
<ActivityIndicator color="white" style={{ marginLeft: 8 }} />
) : null}
</TouchableOpacity>
</View>
);
}
render() {
return (
<View style={styles.container}>
{this.state.loading ? (
<ActivityIndicator size="large" />
) : (
<FlatList
style={{ width: '100%' }}
keyExtractor={(item, index) => index}
data={this.state.serverData}
renderItem={({ item, index }) => (
<View style={styles.item}>
<Text style={styles.text}>
{item.currency}
{'.'}
{item.code}
</Text>
</View>
)}
onEndReached={this.loadMoreData}
onEndReachedThreshold ={0.1}
ItemSeparatorComponent={() => <View style={styles.separator} />}
ListFooterComponent={this.renderFooter.bind(this)}
//Adding Load More button as footer component
/>
)}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
paddingTop: 30,
},
item: {
padding: 10,height:80
},
separator: {
height: 0.5,
backgroundColor: 'rgba(0,0,0,0.4)',
},
text: {
fontSize: 15,
color: 'black',
},
footer: {
padding: 10,
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'row',
},
loadMoreBtn: {
padding: 10,
backgroundColor: '#800000',
borderRadius: 4,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
},
btnText: {
color: 'white',
fontSize: 15,
textAlign: 'center',
},
});
I am new in React and trying to build dynamic form. It seems to work fine. The problem is when i type the field values, they are shown in screen, but the value property of Textinput remain null. I tried to explore all options, and it came down to async of setState. Since i am new i do not know how to make a call back function which can populate the value property of the dynamic form fields.
I have not inlcuded all the code, just what i thought would be relevant to avoid burden.
thanks
sal
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
InputArray: [],
view_data: {
id: 0,
data: null
},
step: 0,
TotalItem: [],
item:
{
id: 0,
Email: null,
Password: null,
Address: null
}
}
};
///onCHANGE FUNCTIONS
EnterValue1 = (e) => {
e.persist();
let item = { ...this.state.item };
item.Email= e.target.value;
this.setState({ item: item });
EnterValue2 = (e) => {
e.persist();
let item = { ...this.state.item };
item.Password = e.target.value;
this.setState({ item: item });
EnterValue3 = (e) => {
e.persist();
let item = { ...this.state.item };
item.Address = e.target.value;
this.setState({ item: item });
//Dynamic form
Inputs = () => {
return (
<View >
<TextInput
placeholder="enter email"
onBlur={this.focusHandler}
value={this.state.item.Email}
onChange={this.EnterValue1}
style={{ borderWidth: 2, borderColor: 'skyblue', margin: 20 }}
/>
<TextInput
placeholder="Password"
onBlur={this.focusHandler}
value={this.state.item.Password}
onChange={this.EnterValue2}
style={{ borderWidth: 2, borderColor: 'skyblue', margin: 20 }}
/>
<TextInput
placeholder="Address"
onBlur={this.focusHandler}
value={this.state.item.Address}
onChange={this.EnterValue3}
style={{ borderWidth: 2, borderColor: 'skyblue', margin: 20 }}
/>
</View>
)
};
// Render Method
render() {
return (
<View style={{ flex: 1, marginTop: 20 }}>
<ScrollView style={styles.scrollView} keyboardShouldPersistTaps='always' >
{this.state.InputArray.map((item, index) => (
//using highlight because it doenst pass on its effect to children, opacity does
<View key={index} onPress={() => this.viewPress(index)}>
<TouchableOpacity onPress={() => this.viewPress(index)}>
{item.data}
{this.state.step === 0 ?
<View style={styles.container}>
<View style={{ flex: 1 }} >
<Button type='button' style={{ flex: 1, backgroundColor: 'red' }} title="add" onPress={this.add} />
</View>
</View>
:
<View style={styles.container}>
<View style={{ flex: 1 }} >
<Button type='submit' style={{ flex: 1, backgroundColor: 'red' }} title="add" onPress={this.add} />
</View>
<View style={{ flex: 1 }}>
<Button type='button' style={{ flex: 1, backgroundColor: 'red' }} title="Remove" onPress={() => this.remove(index)} />
</View>
</View>
}
</TouchableOpacity>
</View>
))
}
</ScrollView>
<View style={styles.container}>
<View style={{ flex: 1 }}>
<Button type='submit' style={{ flex: 1, backgroundColor: 'blue' }} title="submit" onPress={this.submit} />
</View>
</View>
</View>
);
}
}
EnterValue3 = (e) => {
e.persist();
let item = { };
this.setState({ item: {...this.state.item, address: e.target.value });
}
Replace all your function with spread operator rather than directly assigning into the object.
Try this and check
EnterValue1 = (e) => {
e.persist();
this.setState({
item: {
...this.state.item,
Email: e.target.value,
}
});
}
Note: Your whole code may help much to debug your issue
Just in case for someone interested. This may not be the best solution. As this is my first project in react native.
Although i was not able to get the values prop using this.state, and they remained null. For my dynamic form, i made a function containing my Views/textinput with an index argument, provided by my map function(which iterates over an array that has length equal to number of forms added). I used onChageText method and in setState used a callback to save the typed values in an object with an id, that needs to be equivalent to the index of my dynamics mapped form. Using index of object of arrays, values=this.state.object[index],values, is saved in dynamic form.
It still did not populate the values prop, but it sure did maintain the typed content in the front end of the previous form when i add new form.
So I have a component that will render my cards called CardListing as bellow;
return getWalletPayment.map(payment => (
<CardListing
key={payment._id}
card={payment.card}
cardNo={payment.cardNo}
onChanged={selected => {
this.setState({ selectedCard: selected });
}}
/>
));
For now it will render two cards. If I select one everything is fine but if I select the second one the first one will stay selected until I tap on it again to deselect it.
Here is the implementation code
export default class CardListing extends Component {
constructor(props) {
super(props);
this.state = {
selected: false,
scaleCheckmarkValue: new Animated.Value(0)
};
this.scaleCheckmark = this.scaleCheckmark.bind(this);
this.selectPaymentOption = this.selectPaymentOption.bind(this);
}
scaleCheckmark(value) {
Animated.timing(this.state.scaleCheckmarkValue, {
toValue: value,
duration: 400,
easing: Easing.easeOutBack
}).start();
}
selectPaymentOption() {
const { selected } = this.state;
this.setState({
selected: !this.state.selected
});
this.props.onChanged(selected);
}
render() {
const { selected, scaleCheckmarkValue } = this.state;
const { card, cardNo } = this.props;
const number = cardNo.substring(15);
let logo;
if (card == "visa") {
logo = require("../../../assets/images/visa.png");
}
if (card == "master-card") {
logo = require("../../../assets/images/mastercard.png");
}
if (card == "amex") {
logo = require("../../../assets/images/amex.png");
}
if (card == "jcb") {
logo = require("../../../assets/images/jcb.png");
}
if (card == "discover") {
logo = require("../../../assets/images/discover.png");
}
const iconScale = this.state.scaleCheckmarkValue.interpolate({
inputRange: [0, 0.5, 1],
outputRange: [0.01, 1.6, 1]
});
const scaleValue = selected ? 1 : 0;
this.scaleCheckmark(scaleValue);
return (
<View>
<TouchableOpacity
onPress={() => this.selectPaymentOption(this, cardNo)}
style={styles.paymentOptionItem}
>
<View>
<View
style={{
flexDirection: "row",
justifyContent: "space-between"
}}
>
<View style={{ flexDirection: "row" }}>
<Image
source={logo}
style={{
width: 40,
height: 30,
marginTop: 3
}}
/>
<View
style={{
flexDirection: "column"
}}
>
<Text style={styles.paymentOptionTitle}>
{card.toUpperCase()}
</Text>
<Text style={styles.paymentOptionTitle}>Ending {number}</Text>
</View>
</View>
<Animated.View
style={[
{ transform: [{ scale: iconScale }] },
styles.iconWrapper
]}
>
<Icon name="check" color={colors.black} size={20} />
</Animated.View>
</View>
</View>
</TouchableOpacity>
<View style={styles.divider} />
</View>
);
}
}
Any idea how to solve this?
Consider externalising the 'selected' state from the <CardListing/> component, so that the parent component tracks which credit card is currently selected (rather than each <CardListing/> tracking internal state to determine if it is selected).
First lift the selected outside of <CardListing/>, to the parent component. This will involve changes to your parent components map/render function, as shown:
/*
Add this selectedCardId state to parent wallet component and
pass via selectedId. Also pass cardId prop so CardListing can
determine if it is the selected card
*/
return getWalletPayment.map(payment => (
<CardListing
key={payment._id}
card={payment.card}
cardNo={payment.cardNo}
cardId={payment._id}
selectedId={ this.state.selectedCard }
onChanged={selectedId => {
this.setState({ selectedCard: selectedId});
}}
/>
));
Next, revise the implementation of <CardListing/> so that selected is retrieved from this.props rather than this.state, and so that the cardId of the selected card is passed back via the onChanged() callback like so:
selectPaymentOption() {
/*
Pass the id of the card to be selected to callback
*/
this.props.onChanged( this.props.cardId);
}
render() {
/*
Determine if this card should be rendered a the selected
card
*/
const selected = this.selectedId === this.cardId;
/*
Remaining render method remains unchanged
*/
}
Hope this helps!
i want to create rows for images,which recieve from _find function.This function already seperated array to subarrays,which number equals number of rows,how i can render rows with data from _find?Dont purpose ready solutions such as react-native-easy-grid,i want to do it without another libs,and can i scroll items if i use this way?
import React, { Component } from 'react';
import { AppRegistry, Text, TextInput, View,StyleSheet,Button,Image,ScrollView,Dimensions,ListView } from 'react-native';
import Grid from './GridBuilder.js';
const regUrl = /(src=")?(https:\/\/\S{2,500})(")/gm;
var IMAGES_PER_ROW = 3;
let app1;
export default class inputText extends Component {
constructor(props) {
super(props);
app1 = this;
this.state = {
text: null,
findEvent:false,
im_p_r:3,
items:{},
};
}
render() {
return (
<View style={{margin: 20}}>
<TextInput
style = {styles.searchInput}
placeholder="Type here to search"
onChangeText={(text) => this.setState({text})}
/>
<Button
onPress={() => this._find(this.state.text)}s
title='Find'
color="#841584"
accessibilityLabel="on"
/>
{this.state.findEvent && <DisplayImage />}
</View>
);
}
_find(searchText){
fetch('https://www.googleapis.com/customsearch/v1?key=AIzaSyAfcN3jfimFxHxpHNjhHOSuuY8dm5YZnqQ&cx=007223195539364418542:lcqjo0djp7k&num=10&q='+ searchText+'&searchType=image')
.then((resp) => resp.json())
.then(function(data) {
let s = data.items;
let SIZE = IMAGES_PER_ROW;
let res = s.reduce((p,c)=>{
if(p[p.length-1].length == SIZE){
p.link.push([]);
}
p[p.length-1].push(c);
return p.link;
}, [[]])
app1.setState({items:res,findEvent:true});
})
}
}
export class DisplayImage extends Component {
render(){
return(
<View style={styles.container}>
{app1.state.items.map((item,index) => <View style={styles.row} ><Image style={[styles.image,styles.box]} source={{uri:item.link}} key={index} /></View>)}
</View>
)
}
}
const styles = StyleSheet.create({
searchInput:{
fontSize:20,
paddingTop:20,
paddingBottom:20
},
image:{
paddingTop:20,
width:100,
height:100,
},
row: {
flex: 1,
flexWrap: 'wrap',
flexDirection: 'row',
justifyContent: 'space-between'
},
box: {
flex: 1,
height: 100,
width:100,
backgroundColor: '#333',
},
})
AppRegistry.registerComponent('inputText', () => inputText);
AppRegistry.registerComponent('DisplayImage', () => DisplayImage);
You can use FlatList from React Native.
{this.state.findEvent && <FlatList
data={this.state.items}
renderItem={({ item }) => this.renderItem(item)}
/>}
FlatList receive as data the list of elements you want to render, in this case the data returned from the find function.
And then define the renderItem function like:
renderItem(item) {
return (
<View style={styles.row} >
<Image
style={[styles.image,styles.box]}
source={{uri:item.link}} key={index}
/>
</View>
);
}
This function is in charge of rendering the list of images, each image as a row as you want.
FlatList is really useful and makes lists rendering easier. You get the scroll by default and you can also render separators, have a pull to refresh, etc. Take a look to the FlatList doc to see all properties available.
Here is working example of Flat list by which you can get images in the row
https://snack.expo.io/SJDoljDg7
FlatList is the way to go but I suspect the spec has changed since the original accepted answer. You must now provide a key extractor, here is an example of what worked for me:
const listItems = [
{
"id": 0.7967679550647925,
"name": "Hcsrhjkh",
},
{
"id": 0.3212834674770011,
"name": "Phvdgbb",
},
{
"id": 0.30092504022778455,
"name": "Hnvdghbh",
},
]
...
{listItems.length < 1 ? (
<Text style={{ fontSize: 30 }}>Your list is empty.</Text>
) : (
<FlatList
data={listItems}
renderItem={({item}) => <ListItem item={item} />}
keyExtractor={(item) => item.id.toString()}
/>
)}
As you can might have found, the keyExtractor expects a string so I've coerced the 'id' which is a number to a string.
Hi I am starting to use FlatList component instead of ListView and I am having some problems trying to render the separator, I made a multiple-choice component and it is working ok but I don't understand why it is not rendering the separator from the flatlist, if I put the separator inside the renderItem function it's working ok, but I want to use it from the flatlist as a prop.
One curious thing is if I delete the itemSeparatorComponent prop from the FlatList in render method the component stops updating the checkmark (renderIndicator()) that indicates that item is selected, so it's really annoying this, I put the whole code, please check it.
React native: 0.44.0
import React, { Component } from 'react';
import { Button, Icon, Divider } from 'react-native-elements';
import { FlatList, View, TouchableOpacity, Text } from 'react-native';
import { Card, CardSection } from './commons';
import { appMainColor } from '../constants';
export default class ListOrderItems extends Component {
static navigationOptions = {
title: 'Realice su selección'
};
state = { selected: [], items: this.props.navigation.state.params.items };
onItemPress = (item) => {
const selected = this.state.selected;
const index = selected.indexOf(item.name);
if (index === -1) {
selected.push(item.name);
} else {
selected.splice(index, 1);
}
this.setState({ selected });
};
isSelected = (item) => {
return this.state.selected.indexOf(item.name) !== -1;
};
keyExtractor = (item, index) => {
return index;
};
renderOkButton = () => {
if (this.props.navigation.state.params.type === 'multipleChoice') {
return (
<Button
raised
borderRadius={5}
backgroundColor={appMainColor}
title='Aceptar'
onPress={() => this.props.navigation.goBack()}
/>
);
}
};
renderCancelButton = () => {
return (
<Button
raised
borderRadius={5}
backgroundColor={appMainColor}
title='Cancelar'
onPress={() => this.props.navigation.goBack()}
/>
);
};
renderIndicator = (item) => {
if (this.isSelected(item)) {
return <Icon name="check-circle" color={appMainColor} />;
}
};
renderSeparator = () => {
return <Divider />;
};
renderItem = ({ item, index }) => {
return (
<TouchableOpacity
activeOpacity={0.7}
onPress={() => this.onItemPress(item, index)}
>
<View style={styles.row}>
<View style={styles.optionLabel}>
<Text>{item.name} (${item.price})</Text>
</View>
<View style={styles.optionIndicator}>
{this.renderIndicator(item, index)}
</View>
</View>
</TouchableOpacity>
);
};
render() {
return (
<View>
<Card>
<CardSection>
<FlatList
data={this.state.items}
keyExtractor={this.keyExtractor}
renderItem={this.renderItem}
itemSeparatorComponent={() => this.renderSeparator()}
/>
</CardSection>
</Card>
<Card>
<CardSection style={{ justifyContent: 'space-around' }}>
{this.renderOkButton()}
{this.renderCancelButton()}
</CardSection>
</Card>
</View>
);
}
}
const styles = {
row: {
flexDirection: 'row',
padding: 5
},
optionLabel: {
flex: 1,
},
optionIndicator: {
width: 30,
height: 30,
justifyContent: 'center',
alignItems: 'center'
}
};
I think you made some typo, it should be ItemSeparatorComponent, not itemSeparatorComponent.
Flatlist list items are pure components if you want to check with are selected you should set this in the data source you pass in. Otherwise, the props for the item remain the same and the component will not rerender.
For the divider can you try itemSeparatorComponent={Divider}