I am currently implementing a carousel library (react-native-reanimated-carousel). The code for the following is represented as such:
<Carousel
width={cardWidth}
height={cardHeight}
data={cards}
onScrollEnd={() => {console.log('ended')}}
renderItem={({item}) =>
(
<View>
<Image
source={{uri: item["ImgURL"],}}
style={styles.card}
/>
</View>
)}
/>
Upon the carousel changing, the item value in the renderItem property changes. Is there a way to get the value of item from outside this element? I want other elements outside to change depending on the value (and properties) of item.
You could try to call a callback function in the renderItem function.
() => {
const [activeItem, setActiveItem] = useState(cards[0].item);
return (<Carousel
width={cardWidth}
height={cardHeight}
data={cards}
onScrollEnd={() => {console.log('ended')}}
renderItem={({item}) => {
setActiveItem(item);
return (
<View>
<Image
source={{uri: item["ImgURL"],}}
style={styles.card}
/>
</View>
);
}}
/>)
);
};
Or you could use onScrollEnd. It provides the previous index and the current index according to the documentation
() => {
const [activeItem, setActiveItem] = useState(cards[0].item);
return (<Carousel
width={cardWidth}
height={cardHeight}
data={cards}
onScrollEnd={(previous, current) => {
setActiveItem(cards[current].item);
console.log('ended')
}}
renderItem={({item}) => (
<View>
<Image
source={{uri: item["ImgURL"],}}
style={styles.card}
/>
</View>
)}
/>)
);
};
Or you could use the Ref prop getCurrentIndex
Related
I have a component which changes the state when checkbox is checked and the data needs to be updated of the object in the array.
The component state looks something like this
{
key:1,
todo:"Something",
isChecked:false
}
i have 3 files:
AddTodo.js Which passes state & setState to an component TodoList which passes it the subcomponent TodoItem.
I am unable to update the state from TodoItem , I need to implement a function that finds the object from array and updates its isChecked state.
AddTodo.js
function AddTodo() {
const [state, setState] = useState(false);
const [todos, addTodos] = useState([]);
var keys = (todos || []).length;
return (
<View style={styles.container}>
<Modal
animationType="slide"
transparent={true}
visible={state}
statusBarTranslucent={true}
>
<View style={styles.itemsContainer}>
<GetInfoDialog
state={state}
stateChange={setState}
addItem={addTodos}
numKeys={keys}
/>
</View>
</Modal>
{(todos || []).length > 0 ? (
<TodoList data={todos} updateState={addTodos} />
) : null}
<TouchableOpacity
style={styles.btn}
onPress={() => {
setState(true);
}}
>
<Text style={styles.text}>Add New</Text>
</TouchableOpacity>
</View>
);
}
TodoList.js
function TodoList(props) {
return (
<View style={styles.todoList}>
<FlatList
data={props.data}
renderItem={({ item }) => {
console.log(item);
return (
<TodoItem
list={props.data}
itemKey={item.key}
todo={item.todo}
isChecked={item.isChecked}
updateState={props.updateState}
/>
);
}}
backgroundColor={"#000000"}
alignItems={"center"}
justifyContent={"space-between"}
/>
</View>
);
}
TodoItem.js
function TodoItem(props) {
const [checked, setCheck] = useState(props.isChecked);
return (
<View style={styles.todoItem}>
<Checkbox
value={checked}
onValueChange={() => {
setCheck(!checked);
}}
style={styles.checkbox}
/>
<Text style={styles.text}>{props.todo}</Text>
</View>
);
}
renderItem={({ item, index }) => {
console.log(item);
return (
<TodoItem
list={props.data}
itemKey={item.key}
todo={item.todo}
isChecked={item.isChecked}
updateState={props.updateState}
setChecked={(value)=>{
let updatedList = [...yourTodosList]
updatedlist[index].isChecked=value
setTodos(updatedList)
}}
/>
);
}}
and in your todo item
onValueChange={(value) => {
props.setChecked(value);
}}
i also don't think that you need an is checked state in your todo component since you are passing that through props (so delete const [checked, setCheck] = useState(props.isChecked) line and just use the value you are getting from props.isChecked)
didn't pay much attention to your variable names but this should put you on the right track
as per React Native Hooks you have to call
useEffect(() => {
setCheck(checked);
}, [checked]) // now this listens to changes in contact
in TodoItem.tsx
I have two components named Home.js and ViewList.js the user can navigate to each component using a stack navigator.
I want to pass the updatePrice function as a parameter from Home.js to ViewList.js below are snippets on what I am attempting to accomplish.
Here is a brief description of how the app is suppose to work. The user navigates from the Home.js component
to the ViewList.js component. In the View.js component the user has the ability to enter a price for the item.
onChangeText I want to run the updatePrice function so that I can update the state of the list item in the Home.js component.
My problem is that I cannot seem to figure out how to pass the updatePrice function to the ViewList through. Any suggestions
on how I can accomplish this ?
Below is a code snippet for Home.js
export default function Home({navigation}){
const updatePrice = (key, id, price) =>{
setShoppingList(list =>
list.map(list =>
list.key === key
? {
...list,
listItems: list.listItems.map(item =>
item.id === id
? {
...item,
price
}
:item
)
}
: list
)
)
console.log(shoppingLists);
}
return(
<View style={globalStyles.container}>
<FlatList
data={shoppingLists}
renderItem={({ item }) =>(
<TouchableOpacity onPress={() =>
// Here I try to pass the function through the
//navigate prop as an object.
navigation.navigate('ViewList',item,{'updatePrice': () => this.updatePrice})}>
{/*Create card container to wrap text in*/}
<Card>
<Text>{item.name}</Text>
<Text>Budget: $ {item.budget}</Text>
</Card>
</TouchableOpacity>
)}
keyExtractor={item => item.key}
/>
</View>
)
}
Here is another ViewList.js
export default function ViewList({navigation}){
const shoppingListKey = navigation.getParam('key');
const updatePrice = navigation.getParam('updatePrice');
const listInfo = navigation.getParam('listItems');
return(
<View style={globalStyles.container}>
<Card>
<Text>{navigation.getParam('name')}</Text>
<Text>Budget: $ {budget}</Text>
<Text> Total: {total}</Text>
<FlatList
data={listInfo}
renderItem={({item}) =>(
<View>
<Text>{item.name}</Text>
<Text>Price: {item.price}</Text>
<TextInput
style={globalStyles.globalTextInput}
keyboardType={'numeric'}
onChangeText={(value) =>
//Here I try to retrieve the updatePrice function but I got an error.
this.props.navigation.state.params.updatePrice(shoppingListKey,item.id,value)}
/>
</View>
)}
keyExtractor={item => item.id}
/>
</Card>
</View>
)
}
Problem is I cannot see {item.key} inside my function. When I type {item.key} itself inside flatlist render it is working. But inside function only {item.value} is showing. Can anyone explain to me why this happening ?
Sample Data
const orderResultJson = [
{
key: 'Скачайте приложение по ссылке',
value: 'https://google.com'
},
{
key: 'Логин',
value: '879854'
},
{
key: 'Пароль',
value: '849846'
},
];
My Function
function DetailsSection(item){
return(
<View>
<Text>{item.value}</Text>
<Text>{item.key}+test</Text>
</View>
)
}
Render
render() {
return (
<View style={styles.container}>
<FlatList
data={orderResultJson}
renderItem={({item}) => <DetailsSection {...item} />}
keyExtractor={item => item.key}
/>
</View>
);
}
Problem here is, when you are deconstructing item as individual props, the prop key will be considered as in built react prop key instead of considering it as an external prop.
So instead of deconstructing, pass item as is and access it from your function as it is.
My Function
function DetailsSection({ item }){
return(
<View>
<Text>{item.value}</Text>
<Text>{item.key}+test</Text>
</View>
)
}
Render
render() {
return (
<View style={styles.container}>
<FlatList
data={orderResultJson}
renderItem={({item}) => <DetailsSection item={item} />}
keyExtractor={item => item.key}
/>
</View>
);
}
function DetailsSection(props){
return(
<View>
<Text>{props.item.key} + test</Text>
<Text>{props.item.value}</Text>
</View>
)
}
Or
pass like this
<DetailsSection item={item} />
and access like this
function DetailsSection({ item }){
return(
<View>
<Text>{item.value}</Text>
<Text>{item.key}+test</Text>
</View>
)
}
because you are passing extracted value so directly you can access
i'm new in react native and i need your help
i want to give border-bottom to pressed item of horizontal flatlist and border-bottom of Previous item disappear,
now i can give border to new pressed item but i cant remove previous item border
how can i achive this?
enter image description here
these are my Category_style code
state = {
isModalVisible: false,
Index : 0
}
_toggleModal = (index) => {
this.setState({isModalVisible: !this.state.isModalVisible});
this.setState({Index : index});
}
renderProduct(item) {
return <Sub_Categories_FlatList_style name={item.title} icon={item.icon}/>
}
renderSeparator = () => (
<View
style={{
backgroundColor: '#d2d2d2',
height: 0.5,
}}
/>
)
render() {
const {title, index} = this.props;
return (
<View style={pStyles.container}>
<TouchableHighlight onPress={() => this._toggleModal(index)}
style={(index === this.state.Index) ? pStyles.border_bottom : pStyles.no_border_bottom}>
<Text style={pStyles.title}>{title}</Text>
</TouchableHighlight>
<Modal isVisible={this.state.isModalVisible} animationType={'slide'}>
<TouchableOpacity onPress={() => this._toggleModal(index)} style={pStyles.T_opacity}
activeOpacity={.7}>
<Image source={require('./../pictures/x_icon.png')}
style={pStyles.close_image}/>
</TouchableOpacity>
<View style={pStyles.in_modal_view}>
<Text style={pStyles.modal_header_text}>{title}</Text>
<FlatList
data={this.props.subCategory}
renderItem={({item}) => this.renderProduct(item)}
ItemSeparatorComponent={this.renderSeparator}
keyExtractor={(item, index) => index}/>
</View>
</Modal>
</View>
and these are my Category code
static navigationOptions = {
headerStyle: {
backgroundColor: '#4caf50'
},
headerTitle: <Text style={Category_in_style.headerTitleStyle}>Category</Text>
}
renderCategory(item, index) {
return <Category_style title={item.title} index={index} subCategory={item.sub_category}/>
}
renderProduct(item) {
return <Product_style image={item.imageUrl} title={item.title} price={item.price}/>
}
render() {
return (
<View style={{backgroundColor: 'white'}}>
<FlatList style={styles.first_flat}
horizontal
data={this.state.main_categories}
renderItem={({item, index})=> this.renderCategory(item, index)}
keyExtractor={(item, index) => index}/>
<PTRView style={{backgroundColor: '#f1f1f1'}}>
<FlatList style={[{marginTop: 10}, {marginBottom: 50}]}
data={this.state.articles}
renderItem={({item}) => this.renderProduct(item)}
keyExtractor={(item, index) => index}
numColumns={2}/>
</PTRView>
</View>
There may be multiple ways of doing this but I prefer having the parent decide which component is clicked.
So what I suggest is in your renderProduct the item object also has an index which you can pass to your Sub_Categories_FlatList_style and also pass a function to it which basically updates a variable whenever the item is clicked.
Then when you render the list item simply check if it's index matches the currently selected index and then style it accordingly.
Sorry if this seems a bit vague but I'm eyeballing this since I'm at work but I'll be more than happy to answer any follow ups.
I'm a newbie in react native and I'm running into an issue I didn't manage to solve by myself.
So far this is how I am using it:
export default class Form extends React.Component {
state = {index: 0};
_keyExtractor = (item, index) => item.id;
myscrollToIndex = () => {
this.setState({index: ++this.state.index});
this.flatListRef.scrollToIndex({animated: true,index: this.state.index});
};
_renderItem = ({item}) => (
<View>
<Question {...item} />
<Button label='Next' onPress={this.myscrollToIndex} style={styles.buttonNext}/>
</View>
)
render() {
return (
<View style={styles.container}>
<FlatList
horizontal={false}
ref={(ref) => { this.flatListRef = ref; }}
scrollEnabled
data={this.props.form}
extraData={this.state}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem} />
</View>
);
}
}
I would like to pass the index to myscrolltoindex function but I don't manage to as this.flatListRef gets ruled out when I do that.
Have anyone run into a similar issue ?
Thank you for your time
Use index param as well. And pass the index around.
For e.g _renderItem = ({item, index}) => ( <View> <Question {...item} /> <Button label='Next' onPress={this.myscrollToIndex(index) } style={styles.buttonNext}/> </View> )