Can I pass an array to a React Native ScrollView? - react-native

I'm trying to create a scrollable view using React Native's ScrollView with code below
import React from 'react';
import { Image, ScrollView, Text, StyleSheet, View, Dimensions } from 'react-native';
const styles = StyleSheet.create({
scrollView: {
height: '100%',
width: '100%',
flexDirection: 'column',
},
item: {
height: '20%',
width: '100%',
},
});
const data = [];
for (let i = 0; i < 30; i++) {
const datum = (
<View style={styles.item}>
<Text style={{ fontSize: 30 }}>{i.toString()}</Text>
</View>
);
data.push(datum);
}
const App = () => (
<ScrollView style={styles.scrollView}>
{data}
</ScrollView>
);
export default App;
Snack URL: https://snack.expo.io/rp6!W!HZm
When I run this code in Snack, seems like I cannot scroll down to the second page. I've checked the official documentation of ScrollView and it is passing ReactElement individually into the view.
RN official doc: https://reactnative.dev/docs/using-a-scrollview
Does this mean I cannot pass an array of elements as the children of a ScrollView? Is there anything I'm missing here?

This should do exactly what you're asking for!
The main thing happening here is the data mapping in the line
{data.map((item, index) => {
return (<View/>)
}}
where you are defining what is inside the scrollview... also your styling was a tad off so I touched it up.
Hope this helps!
import React from 'react';
import { ScrollView, Text, StyleSheet, View, Dimensions, SafeAreaView, TouchableOpacity } from 'react-native';
const { height } = Dimensions.get('screen');
function App() {
const data = [];
for (let i = 0; i < 30; i++) {
data.push('arbitrary datam #' + (i + 1));
}
return (
<SafeAreaView style={{ flex: 1 }}>
<ScrollView style={styles.scrollView}>
{data.map((item, index) => {
return (
<View key={index} style={styles.item}>
<Text style={{ fontSize: 30 }}>{item}</Text>
</View>
);
})}
</ScrollView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
scrollView: {
height: height,
},
item: {
height: height * 0.2,
width: '100%',
},
});
export default App;

Use flat list:
import React, {Component} from 'react';
import{AsyncStorage, View, ScrollView, FlatList} from 'react-native';
import {Text, List} from 'native-base';
class Notes extends Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
render () {
return (
<ScrollView>
<View style={{margin: 5, marginTop: 5}}>
<List>
<FlatList
data={this.state.data}
renderItem={({item, index}) =>
<View style={styles.item}>
<Text style={{ fontSize: 30 }}>{item.toString()}</Text>
</View>
}
keyExtractor={(item, index) => index.toString()}
/>
</List>
</View>
</ScrollView>
)
}
}
export default Notes;

Related

items doesnt stick to bottom react nativr

im trying to make a to-do list in react native and im trying to make the input and plus bar stick to the bottom and make it go up when i open the keyboard. when i use padding the bar sticks to bottom but i want to use flexbox to make it compatible with all phones. can someone help make stick it to bottom and make it go up with keyboard
task.js
import React from 'react';
import {View, Text, SafeAreaView, StyleSheet, TextInput,KeyboardAvoidingView, TouchableWithoutFeedback, TouchableOpacity} from 'react-native';
const AddTask = () => {
const handleAddTask = () => {
Keyboard.dismiss();
setTaskItems([...taskItems, task])
setTask(null);
}
return (
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
style ={styles.inputbuttons}
>
<TextInput style={styles.input} placeholder={'Write a task'} />
<TouchableOpacity onPress={() => handleAddTask()}>
<View style = {styles.plus}>
<Text>+</Text>
</View>
</TouchableOpacity>
</KeyboardAvoidingView>
);
};
const styles = StyleSheet.create({
input: {
height: 60,
width:320,
margin: 12,
borderWidth: 1,
padding: 10,
borderRadius:20,
},
inputbuttons:{
flexDirection:'row',
alignItems:'center',
justifyContent:'flex-end'
},
plus:{
width:60,
height:60,
borderWidth:1,
borderColor:'black',
textAlign:'right',
borderRadius:'15',
textAlign: 'center',
justifyContent: 'center',
fontSize:30
}
});
export default AddTask;
app.js
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View,Button, Alert,Input } from 'react-native';
import Task from './components/Task';
import AddTask from './components/AddTask';
export default function App() {
return (
<View style={styles.container}>
<View style = {styles.taskWrapper}>
<Text style={styles.header}>Today's Tasks</Text>
</View>
<View style={styles.tasks}>
<Task></Task>
<Task></Task>
</View>
<View>
<AddTask></AddTask>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#E8EAED',
},
taskWrapper:{
paddingTop:80,
paddingHorizontal:20
},
header:{
fontSize:24,
fontWeight:'bold'
},
tasks:{
},
});
You should use KeyboardAvoidingView in your app component so that whenever keyboard gets activated then the component of App gets pushed.

Unable to Apply Layout Animation Using Reanimated API

I'm trying to apply layout animation to a FlatList upon adding and deleting a goal (list item) using the Reanimated API. I'm mainly following this tutorial from the Reanimated docs but I don't know why the animation is not applied when list items are added or removed. I should also inform that I'm only testing this on an Android device. Here is the code:
App.js (contains FlatList)
import { useState } from "react";
import { Button, FlatList, StyleSheet, View } from "react-native";
import GoalInput from "./components/GoalInput";
import GoalItem from "./components/GoalItem";
export default function App() {
const [goalList, setGoalList] = useState([]);
const [isModalOpen, setIsModalOpen] = useState(false);
const styles = StyleSheet.create({
appContainer: {
paddingTop: 50,
},
});
function startAddGoalHandler() {
setIsModalOpen(true);
}
// spread existing goals and add new goal
function addGoalHandler(enteredGoalText) {
setGoalList((currentGoals) => [
...currentGoals,
{ text: enteredGoalText, id: Math.random().toString() },
]);
}
function deleteGoalHandler(id) {
setGoalList((currentGoals) =>
currentGoals.filter((existingGoals) => existingGoals.id !== id)
);
}
return (
<View style={styles.appContainer}>
<Button
title='Add New Goal'
color='indigo'
onPress={startAddGoalHandler}
/>
{isModalOpen && (
<GoalInput
isModalOpen={isModalOpen}
setIsModalOpen={setIsModalOpen}
onAddGoal={addGoalHandler}
></GoalInput>
)}
<FlatList
keyExtractor={(item, index) => {
return item.id;
}}
data={goalList}
renderItem={(itemData) => {
return (
<GoalItem
onGoalDelete={deleteGoalHandler}
itemData={itemData}
/>
);
}}
/>
</View>
);
}
GoalItem.js (list item)
import React from "react";
import { Pressable, StyleSheet, Text } from "react-native";
import Animated, { Layout, LightSpeedInLeft, LightSpeedOutRight } from "react-native-reanimated";
const GoalItem = ({ itemData, onGoalDelete }) => {
const styles = StyleSheet.create({
goalCards: {
elevation: 20,
backgroundColor: "white",
shadowColor: "black",
height: 60,
marginHorizontal: 20,
marginVertical: 10,
borderRadius: 10,
},
});
return (
<Animated.View
style={styles.goalCards}
entering={LightSpeedInLeft}
exiting={LightSpeedOutRight}
layout={Layout.springify()}
>
<Pressable
style={{ padding: 20 }}
android_ripple={{ color: "#dddddd" }}
onPress={() => onGoalDelete(itemData.item.id)}
>
<Text style={{ textAlign: "center" }}>
{itemData.item.text}
</Text>
</Pressable>
</Animated.View>
);
};
export default GoalItem;
I've even tried replacing the FlatList with View but to no avail. I suspect that Reanimated isn't properly configured for my project, if I wrap some components with <Animated.View>...</Animated.View> (Animated from Reanimated and not the core react-native module) for example the child components will not show. Reanimated is installed through npm
Any help is appreciated, thanks!

I need to fix bug with react native. what is the problem?

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
import React, { PureComponent, useState } from 'react'
import { StoryContainer } from 'react-native-stories-view'
import {
TouchableOpacity,
Alert,
StyleSheet,
View,
Text,
SafeAreaView,
ImageBackground,
Image,
Platform,
StatusBar,
} from 'react-native'
import { connect } from 'react-redux'
class StoryViewScreen extends PureComponent {
constructor(props) {
super(props);
this.state = {
}
}
render() {
const { files } = this.props.route.params;
const fileUrls = [];
for (var i = 0; i < files.length; i++) {
fileUrls.push(files[i].uri);
}
console.log("files path:", fileUrls);
return (
<View style={{ flex: 1, flexDirection: 'column' }}>
{Platform.OS === 'ios' && (
<View style={{
backgroundColor: 'gray',
height: 45,
}}>
<StatusBar barStyle="light-content" backgroundColor={'green'} />
</View>
)}
{Platform.OS === 'android' && (
<StatusBar barStyle="dark-content" backgroundColor={'white'} />
)}
<SafeAreaView style={{ flex: 1, flexDirection: 'column', backgroundColor: 'gray' }}>
<StoryContainer
visible={true}
enableProgress={false}
images={fileUrls}
duration={5}
containerStyle={{
width: '100%',
height: '100%',
}} />
{/* <Text>This is teh realdksfjdsklfj</Text> */}
</SafeAreaView>
</View>
);
}
};
const style = StyleSheet.create({
});
function mapStateToProps(state) {
return {
// currentUser: state.user.currentUser,
};
}
function mapDispatchToProps(dispatch) {
return {
dispatch
};
}
export default connect(mapStateToProps, mapDispatchToProps)(StoryViewScreen);
You cannot use useState in class component, instead use setState to set the state.

Failed prop type: invalid prop 'source' supplied to 'ForwardRef(image)'

I am trying to display a simple .jpg image by sending the Image path as a prop to the component which is supposed to render it. In the below way.
App.js
import React, { Component } from 'react';
import { View, Text, Image } from 'react-native';
import Header from './components/Header';
import ImageSlider from './components/ImageSlider';
import ImageShow from './components/ImageShow';
class App extends Component {
render () {
return (
<View style={{flex:1}}>
<Header headerText = "HONEST REVIEWS" />
<ImageSlider />
<ImageShow imagePath = "./abc.jpg"/>
<ImageShow imagePath = "./abc.png" />
</View>
);
}
}
export default App;
ImageShow.js
import React from 'react';
import { View, Image, Dimensions } from 'react-native';
const widthOfScreen = Dimensions.get('window').width;
const ImageShow = (imageProps) => {
return (
<View>
<Image style = { {width: 50, height: 50} } source = { {uri: imageProps.imagePath} } />
</View>
);
};
const styles = {
ImageStyle : {
height: 30,
width: widthOfScreen
}
}
export default ImageShow;
ImageSlider.js
import React from 'react';
import Carousel from 'react-native-banner-carousel';
import { StyleSheet, Image, View, Dimensions } from 'react-native';
const BannerWidth = Dimensions.get('window').width;
const BannerHeight = 250;
const images = [
require('./abc.jpg'),
require('./abc.jpg'),
require('./abc.jpg')
];
export default class ImageSlider extends React.Component {
renderPage(image, index) {
return (
<View key={index}>
<Image style={styles.imagesInSlider} source = { image } />
</View>
);
}
render() {
return (
<View style={styles.container}>
<Carousel
autoplay
autoplayTimeout={2000}
loop
index={0}
pageSize={BannerWidth}
>
{images.map((image, index) => this.renderPage(image, index))}
</Carousel>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
justifyContent: 'flex-start',
alignItems: 'center'
},
imagesInSlider: {
width: BannerWidth,
height: 250,
resizeMode: 'stretch',
}
});
My folder structure is :
ProjectName
------src
--------components
-----------ImageShow.js
-----------ImageSlider.js
-----------Header.js
-----------abc.jpg
--------App.js
Ideally the Image should be displayed when I am passing the locally stored Image path, but I am not getting any Image displayed but a Warning message which says:
"failed prop type: invalid prop 'source' supplied to 'ForwardRef(image)'"
This code work for me to get the image
import image1 from '../assets/images/abc.png'
import image2 from '../assets/images/abc.png'
const images = [
{
name: image1
},
{
name: image2
}]
const RenderPage = ({ image }) => {
return (
<Image resizeMode="contain" style={{ width: 50, height: 100, marginBottom: 5 }} source={image} />
)
}
class myclass extends Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
{images.map((image, index) =>
<RenderPage key={index} image={image.name} />
)}
</View>
)
}
}
Here the screenshot:

Flexbox View does not wrap Image in React Native

When I have an Image inside a View with 'flex: 1' the View does not wrap the Image.
When I paste my code into react-native-web-player it works as expected..
The right image is what I expected, while the left is the actual result:
import * as React from 'react';
import { AppRegistry, View, Image, Text, StyleSheet } from 'react-native';
import SplitView from './components/SplitView';
function PurchaseLine() {
// tslint:disable-next-line:max-line-length
const imgUrl =
'https://cdn.shopify.com/s/files/1/0938/8938/products/10231100205_1_1315x1800_300_CMYK_1024x1024.jpeg?v=1445623369';
return (
<View style={styles.container}>
<Image source={{ uri: imgUrl }} style={styles.img} />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'red'
},
img: {
width: 45,
height: 62
}
});
export default class Datakasse extends React.Component<object, object> {
render() {
return (
<View>
<PurchaseLine />
</View>
);
}
}
AppRegistry.registerComponent('Datakasse', () => Datakasse);
UPDATE:
"height: 100%" or "flex: 1" on the outermost container, and not setting "flex: 1" on PurchaseLine's container seems to work.. Confused why I can't set the latter tho..
import * as React from 'react';
import { AppRegistry, View, Image, Text, StyleSheet } from 'react-native';
import SplitView from './components/SplitView';
function PurchaseLine() {
// tslint:disable-next-line:max-line-length
const imgUrl =
'https://cdn.shopify.com/s/files/1/0938/8938/products/10231100205_1_1315x1800_300_CMYK_1024x1024.jpeg?v=1445623369';
return (
<View style={styles.container}>
<Image source={{ uri: imgUrl }} style={styles.img} />
<Text>1 x Jacket</Text>
<Text>$99.99</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'red',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
padding: 10
},
img: {
width: 45,
height: 62
}
});
export default class Datakasse extends React.Component<object, object> {
render() {
return (
<View style={{ height: '100%', backgroundColor: 'blue' }}>
<PurchaseLine />
</View>
);
}
}
AppRegistry.registerComponent('Datakasse', () => Datakasse);
You can make use of a react-native "hack" and define the width as null like { width: null }. This will make it stretch at 100%. See also the example here based on your code
UPDATE:
the alignSelf what you are looking for. Sample here
UPDATE:
Try this example by setting flex on the parent element and remove from child. Your parent element wasnt defined as flex component so the child had issues. Check here
i removed the flex from container and added here
<View style={{flex: 1}}>