Get the input data from TextInputs which are programatically added using a button - react-native

I've a screen where there is a button to add textInputs. Any no. of inputs can be added by the user. There is another button named submit. When it is tapped, how can I get the appropriate input values. I need them in array eg: [{name1, designation1}, {name2, designation2}, ...].
Code:
App.js
export default class App extends React.Component {
state = {
myArr: []
}
_onPressOut() {
let temp = index ++
this.state.myArr.push(temp)
this.setState({
myArr: this.state.myArr
})
}
_getData() {
//how can I get the data from input values here?
}
render() {
let Arr = this.state.myArr.map((a, i) => {
return <NewComponent />
})
return (
<ScrollView>
<View style={styles.container}>
<Text>Event 1st</Text>
{ Arr }
<Text>Eventlast</Text>
</View>
<TouchableOpacity onPress={() => this._onPressOut()}>
<Text style={{ color: 'green' }}>Add New Component</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this._getData()}>
<View style={{ backgroundColor: 'blue', marginTop: 30 }}>
<Text style={{ color: 'white', textAlign: 'center', marginVertical: 10 }}>Submit</Text>
</View>
</TouchableOpacity>
</ScrollView>
);
}
}
NewComponent.js
class NewComponent extends React.Component{
state = {
name: '',
designation: '',
}
onNameChange = (text) => {
this.setState({
name: text,
});
}
render () {
return (
<View style={{ borderTopWidth:2, borderBottomColor: 'red', paddingTop: 20, marginTop: 30 }}>
<TextInput
placeholder={'Enter Your Name'}
onChangeText={text => {
this.onNameChange(text);
// this.onPropValueChange('SignUpName', text);
}}
value={this.state.name}
style={[{borderBottomColor:'red', borderBottomWidth: 1}]}
/>
<TextInput
placeholder={'Designation'}
onChangeText={text => {
this.onDesignationChange(text);
// this.onPropValueChange('SignUpDesignation', text)
}
}
value={this.state.designation}
style={[{borderBottomColor:'red', borderBottomWidth: 1}]}
/>
</View>
);
}
}

Considering the following assumptions that,until the name is filled,the designation cannot be filled and until the one set of name and designation are filled, the next set of inputs should not be rendered,
In NewComponent.js for the destinationTextInput, make the following changes.
<TextInput
placeholder={'Designation'}
onChangeText={text => {
this.onDesignationChange(text);
// this.onPropValueChange('SignUpDesignation', text)
}
}
value={this.state.designation}
style={[{borderBottomColor:'red', borderBottomWidth: 1}]}
onBlur = {() => {this.props.onNameAndDesignationAdded(this.state.name,this.state.designation)}}
/>
And in App.js add the following
in state object, introduce a new state called resultArr as follows:
state = {
myArr: [],
resultArr : []
}
The _getData function will be as follows:
_getData(name,designation) {
//how can I get the data from input values here?
if(name,designation) {
let tempArr = this.state.resultArr;
tempArr.push({name, designation})
this.setState({resultArr : tempArr})
}
}
The NewComponent called in App.js will have a callback from the TextInput of destination input onBlur method.
let Arr = this.state.myArr.map((a, i) => {
return <NewComponent onNameAndDesignationAdded = {(name,designation) => {
this._getData(name,designation)
} } />
})

Related

Understanding UI State : Dynamic TextInput loses focus after each key press

Screens and navigating is fine, but getting data from users has been a struggle. Not only are the UI elements different, the means to capture input and store in state effectively across various input types is troubling me. Here is an example of what I think is a simple UX yet I cannot get the text inputs to focus correctly.
In the below example, the desire is to have a list of items within a horizontal scroll view and when i click on the arrow of an item, the screen scrolls and a form to edit the item appears with one or more text boxes. Future enhancements were to have this second panel have more fields based on the type of field from the list, but i cant even get a simple text box to work properly
I've got some code to boot, copy and paste as app.js in an expo init project and it should run
main question: how to retain focus on inputs on the detail panel
import React from "react";
import {
Dimensions,
FlatList,
SafeAreaView,
Text,
TextInput,
TouchableOpacity,
View,
} from "react-native";
const init_items = [
{ name: "start", value: 12500, type: "num" },
{ name: "end", value: 12700, type: "num" },
{ name: "time", value: 123.45, type: "time" },
];
const main_color = "#dddddd";
const _base = 3;
const _width = Dimensions.get("window").width;
export default function App() {
const [index, setIndex] = React.useState(0);
const [items, setItems] = React.useState(init_items);
const [curItem, setCurItem] = React.useState("");
const ref = React.useRef(null);
const textRef = React.useRef(null);
React.useEffect(() => {
console.log("index chsnaged?", index);
//if (!index) return;
ref.current?.scrollToIndex({ index, animated: true });
}, [index]);
React.useEffect(() => {
setIndex(curItem === "" ? 0 : 1);
}, [curItem]);
const useCurItem = () => {
if (curItem == "") return;
return items.find((item) => item.name == curItem);
};
const setCurItemValue = (value) => {
console.log("update " + curItem + " to " + value);
const new_items = items.map((item) => {
if (item.name == curItem) return { ...item, value: value };
return item;
});
console.log("new_items: ", new_items);
setItems(new_items);
};
const Button = ({ type, press }) => {
return (
<TouchableOpacity onPress={() => press(type)}>
<Text style={{ fontSize: 20, fontWeight: "900", margin: _base }}>
{type == "arrow" ? ">" : "X"}
</Text>
</TouchableOpacity>
);
};
const ListPanel = () => {
return (
<View>
{items.map((item) => {
return (
<View
key={item.name}
style={{
margin: _base,
}}
>
<Text style={{ fontWeight: "600", margin: _base }}>
{item.name}
</Text>
<View
style={{
alignItems: "center",
backgroundColor: "white",
borderRadius: _base,
flexDirection: "row",
justifyContent: "space-between",
margin: _base,
padding: _base,
}}
>
<Text>{item.value}</Text>
<Button type="arrow" press={() => setCurItem(item.name)} />
{/* <EmojiButton
name={"fat_arrow"}
onPress={() => setCurItem(item.name)}
size={20}
/> */}
</View>
</View>
);
})}
</View>
);
};
const DetailPanel = () => {
let thisItem = useCurItem();
if (!thisItem) return null;
return (
<View style={{ width: "100%" }}>
{/* <EmojiButton name="arrow_left" onPress={() => setCurItem("")} /> */}
<Button type="cancel" press={() => setCurItem("")} />
<Text>{curItem}</Text>
<Text>{thisItem?.value}</Text>
<Text>{thisItem.type}</Text>
{thisItem.type == "num" && (
<TextInput
ref={textRef}
onChangeText={(text) => setCurItemValue(text)}
// onSubmitEditing={() => textRef.current.focus()}
style={{ backgroundColor: "white", margin: 2 }}
value={thisItem.value.toString()}
/>
)}
</View>
);
};
const screens = [
{ name: "listing", panel: <ListPanel /> },
{ name: "detail", panel: <DetailPanel /> },
];
return (
<View style={{ marginTop: 30 }}>
<Text>Sample sliding inputs</Text>
<FlatList
bounces={false}
horizontal
keyExtractor={(item) => item.name}
ref={ref}
showsHorizontalScrollIndicator={false}
data={screens}
renderItem={({ item, index: fIndex }) => {
console.log("rendering " + item);
return (
<View
style={{
backgroundColor: main_color,
height: 300,
width: _width,
padding: _base,
}}
>
<Text> {item.name}</Text>
{item.panel}
</View>
);
}}
/>
<Text>index: {index}</Text>
<Text>curItem: {curItem}</Text>
<TouchableOpacity onPress={() => setCurItem("")}>
<View>
<Text>reset</Text>
</View>
</TouchableOpacity>
</View>
);
}

In React Native can I setState to an object that is in an api call?

This should be something so incredibly easy, but I'm struggling really hard on this. All I want to do is setState of id to "results.id" from my api call. Once it changes the state to what is inside of the api, I will then be able to successfully open up the filmography api. I've tested the axios fetch url by putting in a real id, and it works. So I'm basically trying to grab the id that I get from a search, and update the id state with THAT id. If I'm trying to setState in the wrong function, then by all means help me get it in the right function! (Also I know I have some sloppy code, but a lot of it is personal notes for me until I'm ready to save it for good)
import React, { useState } from "react";
import {
View,
TextInput,
Button,
Text,
ActivityIndicator,
ScrollView,
Image,
TouchableHighlight,
Alert,
} from "react-native";
import Modal from "react-native-modal";
import axios from "axios";
export default function Screen4() {
// id is a 2 digit number for specific actor const apiurl5 = "http://api.tmdb.org/3/search/person?api_key=84c329a92566be57845322a19ff707ac&query=" const apiurl4 = "/movie_credits?api_key=84c329a92566be57845322a19ff707ac&language=en-US" const apiurl3 = "https://api.themoviedb.org/3/person/" const apiurl2 = "https://api.themoviedb.org/3/movie/upcoming?api_key=84c329a92566be57845322a19ff707ac&language=en-US&page=1"; const apiurl = "http://www.omdbapi.com/?apikey=7ad73765&"; const [state, setState] = useState({ s: "Enter an actor...", id: "", results: [], selected: [], modalVisible: false, modalVisible2: false });
const search = () => {
// apiurl + "&t=" + state.s (Single Result)
// apiurl + "&s=" + state.s (Multiple Results)
axios(apiurl5 + state.s).then(({ data }) => {
//let results = [data]; ----- ******** Use this for &t= **************** -------------
//let results = data.Search; ----- ******** Use this for &s= **************** -------------
let results = data.results;
let id = state.id;
setState((prevState) => {
return { ...prevState, modalVisible: true };
}),
setState((prevState) => {
return { ...prevState, results: results };
}),
setState((prevState) => {
return { ...prevState, id: id };
}),
Alert.alert("The ID is: ", id, [
{ text: "Close", onPress: () => console.log("alert closed") },
]);
});
};
const openPopup = () => {
axios(apiurl3 + state.id + apiurl4).then(({ data }) => {
let result = data.cast;
setState((prevState) => {
return { ...prevState, modalVisible2: true };
}),
setState((prevState) => {
return { ...prevState, selected: result };
});
});
};
return (
<View style={{ flex: 1, padding: 10, justifyContent: "center" }}>
<Text>Cinemaster!</Text>
<TextInput
style={{
borderBottomWidth: 1,
borderBottomColor: "#ff0000",
marginBottom: 20,
}}
onChangeText={(text) =>
setState((prevState) => {
return { ...prevState, s: text };
})
}
onSubmitEditing={search}
value={state.s}
/>
<Button onPress={search} title="Search"></Button>
{/* key=result.imdbID -
This gives multiple search results with the &s= is in the URL
key=result -
This gives the result with the &t= is in the URL */}
<Modal
//animationType="slide"
transparent={false}
//visible={(state.modalVisible)}
animationIn="slideInRight"
animationOut="slideOutLeft"
useNativeDriver={true}
isVisible={state.modalVisible}
>
<ScrollView>
{state.results.map((results, index) => (
<TouchableHighlight key={index}>
<View style={{ flex: 1, padding: 10, justifyContent: "center" }}>
<Button title="Full Filmography" onPress={openPopup}></Button>
<Text>Gender: {results.gender}</Text>
<Text>ID: {results.id}</Text>
{results.known_for.map((k, i) => (
<TouchableHighlight
key={i}
// onPress={() => openPopup()}
>
<View>
<Text>Title: {k.title}</Text>
<Image
source={{
uri:
"https://image.tmdb.org/t/p/original/" +
k.poster_path,
}}
style={{ width: 300, height: 500 }}
resizeMode="cover"
/>
</View>
</TouchableHighlight>
))}
{/* <Text>Title: {results.gender}</Text> -----THIS ALSO WORKS----- */}
{/* {dataItems.map((item, index) => (
<div key={index}>
<h1>{item.title}</h1>
{item.content.map((c, i) => (
<div key={i}>
<img src={c.imageUrl} />
<h3>{c.title}</h3>
<h3>{c.description}</h3>
<hr />
</div>
))}
</div>
))} */}
</View>
</TouchableHighlight>
))}
<Text
onPress={() =>
setState((prevState) => {
return { ...prevState, modalVisible: false };
})
}
style={{
marginTop: 50,
color: "red",
fontSize: 40,
fontWeight: "bold",
}}
>
Close!
</Text>
</ScrollView>
</Modal>
{/* animationType in Modal can be fade, none, or slide */}
<Modal
//animationType="slide"
transparent={false}
//visible={(state.modalVisible)}
animationIn="slideInRight"
animationOut="slideOutLeft"
useNativeDriver={true}
isVisible={state.modalVisible2}
>
<ScrollView>
{state.selected.map((cast, index2) => (
<View key={index2}>
<Text>Title:{cast.title} </Text>
<Text>Overview:{cast.overview} </Text>
</View>
))}
</ScrollView>
<TouchableHighlight
onPress={() =>
setState((prevState) => {
return { ...prevState, modalVisible2: false };
})
}
>
<Text
style={{
marginTop: 50,
color: "red",
fontSize: 40,
fontWeight: "bold",
}}
>
Close!
</Text>
</TouchableHighlight>
</Modal>
</View>
);
}
API for results.id :
http://api.tmdb.org/3/search/person?api_key=84c329a92566be57845322a19ff707ac&query=tom%20hanks
API for filmography:
https://api.themoviedb.org/3/person/31/movie_credits?api_key=84c329a92566be57845322a19ff707ac&language=en-US
Attached an image, showing the ID I'm trying to setState inPhoneExample
I figured it out. I had to use a for loop in order to get the data I needed in order to then set that data. What wasn't clear to me at first, was if that was necessary or not, and if it was I assumed I had to do that in the section of my code where I was mapping things. But no, once I got a for loop going in that search function it started to make sense to me.

How to use ScrollToIndex in React Native?

I use a FlatList to display search results.
<View>
<FlatList
data={this.state.films}
keyExtractor={(item) => item.id.toString()}
renderItem={({item}) => <FilmItem film={item}/>}
/>
</View>
However, when the user starts a second search, this list does not restart to index 0. So I would like to add ScrollToIndex or viewPosition. I tried this but it doesn't work :
<View>
<FlatList
data={this.state.films}
keyExtractor={(item) => item.id.toString()}
renderItem={({item}) => <FilmItem film={item}/>}
scrollToItem={(index) => {0}}
/>
</View>
Could you please explain me why this is wrong and what would be the best solution ?
Thanks a lot,
Try this... I made a bunch of changes and have put comments:
// Components/Search.js
import React from "react";
import {StyleSheet, View, TextInput, Button, Text, FlatList, ActivityIndicator} from "react-native";
import FilmItem from "./filmItem";
import {getFilmsFromApiWithSearchedText} from "../API/TMDBApi";
class Search extends React.Component {
flatListRef = null; // declaring this here to make it explicit that we have this available
constructor(props) {
super(props);
this.searchedText = "";
this.state = {
films: [],
isLoading: false,
};
}
_loadFilms = () => {
// needs to be an arrow function so `this` is bound to this component
this.scrollToIndex(); // assumed you meant to actually call this?
if (this.searchedText.length > 0) {
this.setState({isLoading: true});
getFilmsFromApiWithSearchedText(this.searchedText).then(data => {
this.setState({
films: data.results,
isLoading: false,
});
});
}
};
// needs arrow to use `this`
_searchTextInputChanged = text => {
this.searchedText = text;
};
// needs arrow to use `this`
_displayLoading = () => {
// better to return null if not loading, otherwise return loading indicator
if (!this.state.isLoading) return null;
return (
<View style={styles.loading_container}>
<ActivityIndicator size='large' />
</View>
);
};
scrollToIndex = () => {
// you previously had this inside another method
this.flatListRef && this.flatListRef.scrollToIndex({index: 1}); // checking it exists first
};
render() {
return (
<View style={styles.main_container}>
<TextInput
style={styles.textinput}
placeholder='Titre du film'
onChangeText={text => this._searchTextInputChanged(text)}
onSubmitEditing={this._loadFilms} // no need to create a new anonymous function here
/>
<Button title='Rechercher' onPress={this._loadFilms} />
<View>
<FlatList
data={this.state.films}
ref={ref => (this.flatListRef = ref)}
keyExtractor={item => item.id.toString()}
onEndReachedThreshold={1} // corrected typo
onEndReached={() => {
console.log("TOC");
}}
renderItem={({item}) => <FilmItem film={item} />}
/>
</View>
{this._displayLoading()}
</View>
);
}
}
const styles = StyleSheet.create({
main_container: {
marginTop: 60,
padding: 15,
flex: 1,
},
loading_container: {
position: "absolute",
left: 0,
right: 0,
top: 100,
bottom: 0,
alignItems: "center",
paddingTop: 50,
backgroundColor: "white",
},
textinput: {
height: 50,
borderColor: "#999999",
borderWidth: 1,
paddingLeft: 5,
},
});
export default Search;
Using this code as example:
import React, { Component } from 'react';
import { Text, View, FlatList, Dimensions, Button, StyleSheet } from 'react-native';
const { width } = Dimensions.get('window');
const style = {
justifyContent: 'center',
alignItems: 'center',
width: width,
height: 50,
flex: 1,
borderWidth: 1,
};
const COLORS = ['deepskyblue','fuchsia', 'lightblue '];
function getData(number) {
let data = [];
for(var i=0; i<number; ++i)
{
data.push("" + i);
}
return data;
}
class ScrollToExample extends Component {
getItemLayout = (data, index) => (
{ length: 50, offset: 50 * index, index }
)
getColor(index) {
const mod = index%3;
return COLORS[mod];
}
scrollToIndex = () => {
let randomIndex = Math.floor(Math.random(Date.now()) * this.props.data.length);
this.flatListRef.scrollToIndex({animated: true, index: randomIndex});
}
scrollToItem = () => {
let randomIndex = Math.floor(Math.random(Date.now()) * this.props.data.length);
this.flatListRef.scrollToIndex({animated: true, index: "" + randomIndex});
}
render() {
return (
<View style={styles.container}>
<View style={styles.header}>
<Button
onPress={this.scrollToIndex}
title="Tap to scrollToIndex"
color="darkblue"
/>
<Button
onPress={this.scrollToItem}
title="Tap to scrollToItem"
color="purple"
/>
</View>
<FlatList
style={{ flex: 1 }}
ref={(ref) => { this.flatListRef = ref; }}
keyExtractor={item => item}
getItemLayout={this.getItemLayout}
initialScrollIndex={50}
initialNumToRender={2}
renderItem={({ item, index}) => (
<View style={{...style, backgroundColor: this.getColor(index)}}>
<Text>{item}</Text>
</View>
)}
{...this.props}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
header: {
paddingTop: 20,
backgroundColor: 'darkturquoise',
alignItems: 'center',
justifyContent: 'center'
}
});
export default class app extends Component {
render() {
return <ScrollToExample
data={getData(100)}
/>
}
}
I tried to add a ref but it doesn't work :
// Components/Search.js
import React from 'react'
import { StyleSheet, View, TextInput, Button, Text, FlatList, ActivityIndicator } from 'react-native'
import FilmItem from './filmItem'
import { getFilmsFromApiWithSearchedText } from '../API/TMDBApi'
class Search extends React.Component {
constructor(props) {
super(props)
this.searchedText = ""
this.state = {
films: [],
isLoading: false,
}
}
_loadFilms() {
{this.scrollToIndex}
if (this.searchedText.length > 0) {
this.setState({isLoading: true})
getFilmsFromApiWithSearchedText(this.searchedText).then(data => {
this.setState({
films: data.results,
isLoading: false
})
})
}
}
_searchTextInputChanged(text) {
this.searchedText = text
}
_displayLoading() {
if (this.state.isLoading) {
return (
<View style={styles.loading_container}>
<ActivityIndicator size='large'/>
</View>
)
}
scrollToIndex = () => {
this.flatListRef.scrollToIndex({index: 1});
}
}
render() {
return (
<View style={styles.main_container}>
<TextInput
style={styles.textinput}
placeholder='Titre du film'
onChangeText={(text) => this._searchTextInputChanged(text)}
onSubmitEditing={() => this._loadFilms()}
/>
<Button title='Rechercher' onPress={() => this._loadFilms()} />
<View>
<FlatList
data={this.state.films}
ref={(ref) => { this.flatListRef = ref; }}
keyExtractor={(item) => item.id.toString()}
onEndReachedThreashold={1}
onEndReached={() => {console.log("TOC")}}
renderItem={({item}) => <FilmItem film={item}/>}
/>
</View>
{this._displayLoading()}
</View>
)
}
}
const styles = StyleSheet.create({
main_container: {
marginTop: 60,
padding: 15,
flex: 1,
},
loading_container: {
position: 'absolute',
left: 0,
right: 0,
top: 100,
bottom: 0,
alignItems: 'center',
paddingTop: 50,
backgroundColor: 'white',
},
textinput: {
height: 50,
borderColor: '#999999',
borderWidth: 1,
paddingLeft: 5,
}
})
export default Search
I'm sur I am doing something wrong, but don't find the error. Thanks a lot for your help.

What am I doing wrong with my code here I'm so lost

I'm trying to input my firestore into the form and put all my user data so I can pass information as
profile.name
profile.email
profile.location
profile.avatar
so what am I doing wrong here to keep on receiving this error?
Error
This is my mock screen
import Fire from '../utilities/Fire';
super(props);
this.state = {
user: {}
}
const user = this.props.uid || Fire.shared.uid
this.unsubscribe = Fire.shared.firestore
.collection("users")
.doc(user)
.onSnapshot(doc => {
this.setState({ user: doc.data() });
});
this.unsubscribe();
unsubscribe = null;
const profile = {
username: this.state.user.name,
location: this.state.user.location,
email: this.state.user.email,
avatar: this.state.user.avatar ? { uri: this.state.user.avatar } : require("../assets/avatar.png"),
notifications: true,
};
export { profile };
This is my Settings Page
import React, { Component } from "react";
import { Image, StyleSheet, ScrollView, TextInput } from "react-native";
import { Divider, Button, Block, Text, Switch } from "../components";
import { theme, mock } from "../constants";
class Settings extends Component {
state = {
notifications: true,
editing: null,
profile: {}
};
componentDidMount() {
this.setState({ profile: this.props.profile });
}
handleEdit(name, text) {
const { profile } = this.state;
profile[name] = text;
this.setState({ profile });
}
toggleEdit(name) {
const { editing } = this.state;
this.setState({ editing: !editing ? name : null });
}
renderEdit(name) {
const { profile, editing } = this.state;
if (editing === name) {
return (
<TextInput
defaultValue={profile[name]}
onChangeText={text => this.handleEdit([name], text)}
/>
);
}
return <Text bold>{profile[name]}</Text>;
}
render() {
const { profile, editing } = this.state;
return (
<Block>
<Block flex={false} row center space="between" style={styles.header}>
<Text h1 bold>
Settings
</Text>
<Button>
<Image source={profile.avatar} style={styles.avatar} />
</Button>
</Block>
<ScrollView showsVerticalScrollIndicator={false}>
<Block style={styles.inputs}>
<Block row space="between" margin={[10, 0]} style={styles.inputRow}>
<Block>
<Text gray2 style={{ marginBottom: 10 }}>
Username
</Text>
{this.renderEdit("username")}
</Block>
<Text
medium
secondary
onPress={() => this.toggleEdit("username")}
>
{editing === "username" ? "Save" : "Edit"}
</Text>
</Block>
<Block row space="between" margin={[10, 0]} style={styles.inputRow}>
<Block>
<Text gray2 style={{ marginBottom: 10 }}>
Location
</Text>
{this.renderEdit("location")}
</Block>
<Text
medium
secondary
onPress={() => this.toggleEdit("location")}
>
{editing === "location" ? "Save" : "Edit"}
</Text>
</Block>
<Block row space="between" margin={[10, 0]} style={styles.inputRow}>
<Block>
<Text gray2 style={{ marginBottom: 10 }}>
E-mail
</Text>
<Text bold>{profile.email}</Text>
</Block>
</Block>
</Block>
<Divider margin={[theme.sizes.base, theme.sizes.base * 2]} />
<Divider />
<Block style={styles.toggles}>
<Block
row
center
space="between"
style={{ marginBottom: theme.sizes.base * 2 }}
>
<Text gray2>Notifications</Text>
<Switch
value={this.state.notifications}
onValueChange={value => this.setState({ notifications: value })}
/>
</Block>
</Block>
</ScrollView>
</Block>
);
}
}
Settings.defaultProps = {
profile: mock.profile
};
export default Settings;
const styles = StyleSheet.create({
header: {
paddingHorizontal: theme.sizes.base * 2
},
avatar: {
height: theme.sizes.base * 2.2,
width: theme.sizes.base * 2.2
},
inputs: {
marginTop: theme.sizes.base * 0.7,
paddingHorizontal: theme.sizes.base * 2
},
inputRow: {
alignItems: "flex-end"
},
sliders: {
marginTop: theme.sizes.base * 0.7,
paddingHorizontal: theme.sizes.base * 2
},
thumb: {
width: theme.sizes.base,
height: theme.sizes.base,
borderRadius: theme.sizes.base,
borderColor: "white",
borderWidth: 3,
backgroundColor: theme.colors.secondary
},
toggles: {
paddingHorizontal: theme.sizes.base * 2
}
});
Tried to add a class function to fix it but now it's not recognized my profile on my const, tried to change the class name to mock and export both mock and profile but not working any tips?
fixed the first error but now I am getting a second error with my setState
The error is pretty informative.
You can not have super() sitting outside of a class constructor.
Here would be a working example of that:
class YourComponentName extends Component {
constructor( props ) {
super( props )
this.state = {
user: {}
}
}
...
}
export default YourComponentName
More info on super: https://overreacted.io/why-do-we-write-super-props/
While this should resolve the error you're getting, it probably will not resolve your underlying issue. I recommend researching React state machines.
super(props); should be used inside constructor on the class. So just wrap your super and state in the constructor or remove super completely.

React Native FlatList Touchable Opacity

I used FlatList to display the title that is in the data. I added in TouchableOpacity for the FlatList. So for example, when I click 'First', I want to show the the data from 'mood' and it will show the list of passionate,rousing and confident. I want to show the list on a new file/screen and show purely the mood of list.
This is my data:
const Mock =
[
{ title: 'First',
mood:
[
{name: 'passionate'},
{name: 'rousing'},
{name: 'confident'},
],
},
{ title: 'Second',
mood:
[
{name: 'rollicking'},
{name: 'cheerful'},
{name: 'fun'},
{name: 'sweet'},
{name: 'amiable'},
{name: 'natured'}
],
This is my FlatList code:
export default class Cluster1 extends Component{
render() {
return (
<View>
<FlatList
data={Mock}
renderItem={({ item, index }) => {
return <FlatListItem item={item} index={index} />;
}}
/>
</View>
);
}
}
class FlatListItem extends Component {
render() {
return (
<View style={styles.list}>
<View>
<TouchableOpacity>
<Text style={styles.itemTitle}>{this.props.item.title}</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
What should I do with the TouchableOpacity when I want to show the mood name when I click the title?
This is my style code
const styles = StyleSheet.create({
itemTitle:{
fontSize: 25,
fontWeight: 'bold',
color: 'white',
margin: 20,
},
},
list:{
flex: 1,
backgroundColor: '#00BCD4',
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
},
});
You should modify your code as below to do this:
export default class Cluster1 extends Component {
render() {
return (
<View style={{ margin: 30, backgroundColor: '#ddd' }}>
<FlatList
data={Mock}
renderItem={({ item, index }) => {
return <FlatListItem item={item} index={index} />;
}}
/>
</View>
);
}
}
class FlatListItem extends Component {
state = { showItemIndex: [false, false] };
_onPress = index => () => {
let showItemIndex = this.state.showItemIndex;
showItemIndex[index] = !this.state.showItemIndex[index];
this.setState({ showItemIndex });
};
render() {
return (
<View style={styles.list}>
<View>
<TouchableOpacity onPress={this._onPress(this.props.index)}>
<Text style={styles.itemTitle}>{this.props.item.title}</Text>
</TouchableOpacity>
{this.state.showItemIndex[this.props.index] && (
<FlatList
data={this.props.item.mood}
extraData={this.state.showItemIndex}
renderItem={({ item, index }) => {
return (
<Text item={item} index={index}>
{item.name}
</Text>
);
}}
/>
)}
</View>
</View>
);
}
}
Use this, it's should be work fine for you:
Link: https://github.com/oblador/react-native-collapsible
Link: https://github.com/naoufal/react-native-accordion
Link: https://github.com/cuiyueshuai/react-native-expandable-section-flatlist
You could set a state variable which gets updated whenever your TouchableOpacity gets pressed. And then you conditionally render the title or the list of mood names:
class FlatListItem extends Component {
constructor(props) {
super(props);
this.state = {collapsed: true}
}
render() {
return (
<View style={styles.list}>
<View>
<TouchableOpacity
onPress={this.onPress}
>
<Text style={styles.itemTitle}>
{this.props.item.title}
</Text>
</TouchableOpacity>
{this.state.collapsed ?
<View /> :
<View>
{this.props.item.mood.map(mood => <Text>{mood.name}</Text>)}
</View>}
</View>
</View>
);
}
onPress = () => {
this.setState({collapsed: !this.state.collapsed})
}
}
You can do this by separating out the datasource that is required to show in the list.
First to display title: you can do something like this
export default class Cluster1 extends Component {
state = {
data: []
};
componentWillMount() {
const titles = Mock.forEach(data => data.title);
this.setState({
data: titles
});
}
onItemClick = item => {
const itemIndex = Mock.findIndex(data => (
data.title === item
));
const values = Mock[itemIndex].mood;
this.setState({
data: values
});
};
render() {
return (
<View>
<FlatList
data={this.state.data}
renderItem={({ item, index }) => {
return (
<FlatListItem
item={item}
index={index}
onItemClick={this.itemClick}
/>
);
}}
/>
</View>
);
}
}
and then in your FlatlistItem code:
class FlatListItem extends Component {
render() {
return (
<View style={styles.list}>
<View>
<TouchableOpacity onPress={() =>
this.props.onItemClick(this.props.item)
}>
<Text style={styles.itemTitle}>
{
this.props.item.name ?
this.props.item.name : this.props.item
}
</Text>
</TouchableOpacity>
</View>
</View>
);
}
}