I have this nested array
[
{
"id": 1,
"title": "Question 1",
"answers": [
{
"options": 1,
"right_ans": "yes"
},
{
"options": 2,
"right_ans": "no"
}
]
},
{
"id": 2,
"title": "Question 2",
"answers": [
{
"options": 1,
"right_ans": "yes"
},
{
"options": 2,
"right_ans": "no"
}
]
}
]
I have this code in react native
import questions from './questions '
const [data, setdata] = useState([]);
useEffect(() => {
setdata(questions);
}, [])
onChangeValue = (itemSelected, index) => {
// console.log(index);
const newData = data.map(item => {
//console.log(item.answers[index].options)
console.log(item.answers[index].options+':'+itemSelected.options)
//console.log();
if (item.answers[index].options == itemSelected.options) {
return {
...item,
checked : !item.checked
}
}
return {
...item,
checked : item.checked
}
})
//console.log(newData);
setdata(newData)
}
renderItem = ({item, index}) => {
return (
<View>
<Text>Nueov</Text>
<View style={styles.item}>
<Text>{item.title}</Text>
<FlatList
data={item.answers}
renderItem={({ item }) =>
<View>
{item.checked}
<CheckBox
key={item.options}
size={40}
checked={item.checked}
style={styles.ckItem}
onPress={()=> onChangeValue(item, index)}
/>
<View style={styles.WrapText}>
<Text>{item.right_ans}</Text>
</View>
</View>
}
keyExtractor={item => item.options}
/>
</View>
</View>
)
}
onShowItemSelected = () => {
const listSelected = data.filter(item => item.checked == true);
let contentAlert = '';
listSelected.forEach(item=>{
contentAlert = contentAlert + `${item.id}.`+item.apartado+ `\n`;
})
Alert.alert(contentAlert);
}
return (
<SafeAreaView style={styles.container}>
<FlatList
style={styles.list}
data={data}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
<View styles={styles.wrapButton}>
<TouchableOpacity style={styles.button} onPress={onShowItemSelected}>
<Text>Mostrar el elemento que seleccionados</Text>
</TouchableOpacity>
</View>
</SafeAreaView>
)
}
When I select any checkbox that runs through me, it measures a 1:1 or 2:1 value, which means the number of the object and the answer I select, I still cannot update the array to be able to incorporate a checked object to know which answer I select
Related
export const Data = [
{
id:'adkdkdkdk',
title:'first',
},
{
id:'mvmvmvvm',
title:'second',
},
{
id:'newoq',
title:'third',
},
{
id:'dnkdlnsdl',
title:'four'
}
]
this is data
const University = () => {
const navigation = useNavigation();
return (
<Container>
<FlatList horizontal data={Data} renderItem={({item})=> (
<TextContainer onPress={()=> navigation.navigate('Stack',{screen:'Information',params:{item}})}>
<Texts>{item.title}</Texts>
<Texts>{item.id}</Texts>
</TextContainer>
)} keyExtractor={key=>key.id}/>
</Container>
)
}
and this is code
I want to send params to Information screen, so I used navigation and send params but params is 'undefined' when console.log... what is problem?
here is a working code:
const data = [
{
id:'adkdkdkdk',
title:'first',
},
{
id:'mvmvmvvm',
title:'second',
},
{
id:'newoq',
title:'third',
},
{
id:'dnkdlnsdl',
title:'four'
}
];
return (
<View style={styles.container}>
<FlatList
data={data}
keyExtractor={item => item.id}
renderItem={({ item }) => (
<>
<Text>{item.id}</Text>
<Text>{item.title}</Text>
</>
)}
/>
</View>
);
}
*I use the ref property in the flatlist component in react native, but I get an undefined is not an
object error. I looked at many places on
the internet but did not get a satisfactory answer. Please help me :)*
const DATA = [
{
id: 0,
title: "First Item",
},
{
id: 1,
title: "Second Item",
},
];
const [selectedId, setSelectedId] = useState(null);
**React.useEffect(() => {
this.el.scrollToIndex({ animated: true, index:selectedId});
}, []);**
const Item = ({ item, onPress, style }) => (
<TouchableOpacity onPress={onPress} style={[styles.item, style]}>
<Text style={styles.title}>{item.title}</Text>
</TouchableOpacity>
);
const renderItem = ({ item }) => {
const backgroundColor = item.id === selectedId ? "#6e3b6e" : "#f9c2ff";
return (
<Item
item={item}
onPress={() => setSelectedId(item.id)}
style={{ backgroundColor }}
/>
);
};
return (
<>
<FlatList
data={DATA}
horizontal={true}
renderItem={renderItem}
keyExtractor={(item) => item.id}
extraData={selectedId}
**ref={(el) => this.el = el}**strong text
/>
</>
)
}```
To use a ref, you need to use useRef (since you're on a function component). On function components you won't find yourself using this. When using useRef, you'll need to use .current to access the item itself. So, you can see I'm doing el.current.scrollToIndex
Also, you'll need to add selectedId as a dependency to your useEffect
export default function App() {
const DATA = [
{
id: 0,
title: "First Item",
},
{
id: 1,
title: "Second Item",
},
{
id: 2,
title: "Second Item",
},
{
id: 3,
title: "Second Item",
},
{
id: 4,
title: "Second Item",
},
{
id: 5,
title: "Second Item",
},
{
id: 6,
title: "Second Item",
},
];
const [selectedId, setSelectedId] = React.useState(null);
const el = React.useRef()
React.useEffect(() => {
el.current.scrollToIndex({ animated: true, index:selectedId});
}, [selectedId]);
const Item = ({ item, onPress, style }) => (
<TouchableOpacity onPress={onPress} style={[styles.item, style]}>
<Text style={styles.title}>{item.title}</Text>
</TouchableOpacity>
);
const renderItem = ({ item }) => {
const backgroundColor = item.id === selectedId ? "#6e3b6e" : "#f9c2ff";
return (
<Item
item={item}
onPress={() => setSelectedId(item.id)}
style={{ backgroundColor }}
/>
);
};
return (
<>
<FlatList
data={DATA}
horizontal={true}
renderItem={renderItem}
keyExtractor={(item) => item.id}
extraData={selectedId}
ref={el}
/>
</>
)
}
here is the app, I want to create diferent screens with diferent catergories in this case I have Dermatologista and Hospital, how can I select just one description
const [state, setState] = useState({
places: [
{
id: 1,
title: 'Clinica da pele',
description: 'Dermatologista',
latitude:-2.42206406,
longitude:-54.71947789,
},
{
id: 2 ,
title:'Unimed',
description:'Hospital',
latitude:-2.42501721,
longitude:-54.71146077,
},
{
id: 3,
title: 'Dra. Josimar',
description:'Dermatologista',
latitude: -2.4288346,
longitude:-54.7290553,
}
]
});
return(
I just want to select the items with the description == dermatologista
how can I do this ?
<SafeAreaView>
<FlatList
styles = {styles.PlaceContainer}
showsVerticalScrollIndicator
data={state.places}
keyExtractor={item => item.id}
renderItem={({ item }) => {
return(
<View key={item.id} style={styles.place} >
<Text>{item.title}</Text>
<Text>{item.description}</Text>
</View>
)
}
}
/>
</SafeAreaView>
)
}
You can use array.filter :
const filteredPlaces = state.places.filter( place => place.description === "Dermatologista" )
and pass filteredPlaces instead of the entire object to the child component.
Try this
<SafeAreaView>
<FlatList
styles = {styles.PlaceContainer}
showsVerticalScrollIndicator
data={state.places}
keyExtractor={item => item.id}
renderItem={({ item }) => {
item.description == "dermatologista" ? (
<View key={item.id} style={styles.place} >
<Text>{item.title}</Text>
<Text>{item.description}</Text>
</View>
):""
}
}
/>
</SafeAreaView>
I'm trying to add this object { "origin": "user", "message": this.state.message } to the messages arraylist by using setState. Right now I'm getting the following error:
Invariant Violation: Objects are not valid as React child (found:object with keys {origin, message})
Also, if there is a better way than setTimeout to wait until the message has been rendered before scrolling to the bottom that would be cool aswell!
sendMessage = () => {
this.setState(prevState => ({
messages: [...prevState.messages, { "origin": "user", "message": this.state.message }]
}));
this.callChatService().then((responseJson) => {
this.setState({
context: responseJson.context
});
for (var i = 0; i < responseJson.output.generic.length; i++) {
this.setState(prevState => ({
messages: [...prevState.messages, { "origin": "bot", "message": responseJson.output.generic[i].text}]
}));
}
})
setTimeout(() => this.refs.flatList.scrollToEnd(), 1500);
this.setState({
message: ""
})
}
renderItem = ({ item }) => {
if (item.origin == "user") {
return (
<View>
<View style={styles.rowRight}>
<Text style={styles.message}>{item}</Text>
</View>
</View>
);
}
else {
return (
<View>
<View style={styles.rowLeft}>
<Text style={styles.message}>{item}</Text>
</View>
</View>
);
}
}
componentWillMount() {
}
render() {
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.title}>{this.state.header}</Text>
</View>
<FlatList
style={styles.list}
ref="flatList"
data={this.state.messages}
keyExtractor={(item, index) => index}
renderItem={this.renderItem}
/>
<KeyboardAvoidingView behavior="padding" keyboardVerticalOffset={20}>
<View style={styles.footer}>
<TextInput
value={this.state.message}
onChangeText={text => this.setState({ message: text })}
style={styles.input}
underlineColorAndroid="transparent"
placeholder="Ask me anything"
/>
<TouchableOpacity onPress={this.sendMessage} style={styles.sendButton} >
<Icon name="send" type="material-icon" size={28} color="#00B2EE" />
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
</View>
);
}
The issues lies in those lines of your renderItem method:
<Text style={styles.message}>{item}</Text>
item in this context is an object and can not be rendered by the Text component, hence the error.
Considering your code, I believe it should have been item.message like so:
<Text style={styles.message}>{item.message}</Text>
I want to develop a React Native app, and I want to have locally stored some data of the format:
[
{
"id": 1,
"text": "Lorem ipsum",
"viewed": false
},
{
"id": 2,
"text": "Second lorem",
"viewed": false
},
{
"id": 3,
"text": "Last lorem",
"viewed": false
}
]
I want this data to be available when the user first downloads the app. Then based on the user's navigation, the corresponding data in the db will change the viewed flag to true. This has to be persistent when the app will be updated by the user on the next version.
Any tips/ideas on how to achieve this?
Currently I'm looking into Realm.io but I'm not sure if this is the right tool for me.
You can use AsyncStorage for that like so:
const data = [
{
"id": 1,
"text": "Lorem ipsum",
"viewed": false
},
{
"id": 2,
"text": "Second lorem",
"viewed": false
},
{
"id": 3,
"text": "Last lorem",
"viewed": false
}
]
try {
await AsyncStorage.setItem(
'SOME_KEY', JSON.stringify(data)
);
} catch (error) {
// Handle error
}
Later on if you want to fetch/change you can do:
AsyncStorage.getItem('SOME_KEY', (err, result) => {
console.log(JOSN.parse(result));
});
If data is more than pouchDb is suggested option.
You can install it with
npm install pouchdb-react-native --save
Simple Demo
import PouchDB from 'pouchdb-react-native'
const db = new PouchDB('mydb')
// use PouchDB
db.get('4711')
.then(doc => console.log(doc))
Advance Demo
'use strict'
import React from 'react'
import {
AsyncStorage,
ListView,
Navigator,
StyleSheet,
Text,
TextInput,
TouchableHighlight,
View
} from 'react-native'
import ActionButton from 'react-native-action-button'
import PouchDB from 'pouchdb-react-native'
const localDB = new PouchDB('myDB')
console.log(localDB.adapter)
AsyncStorage.getAllKeys()
.then(keys => AsyncStorage.multiGet(keys))
.then(items => console.log('all pure Items', items))
.catch(error => console.warn('error get all Items', error))
export default React.createClass({
getInitialState () {
const updateDocs = () => {
localDB.allDocs({include_docs: true, limit: null})
.then(result => {
const items = result.rows.map(row => row.doc)
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1.id !== r2.id})
this.setState({
dataSource: ds.cloneWithRows(items),
count: items.length
})
})
.catch(error => console.warn('Could not load Documents', error, error.message))
}
localDB.changes({since: 'now', live: true})
.on('change', () => updateDocs())
updateDocs()
return {
dataSource: null,
syncUrl: 'http://localhost:5984/test'
}
},
render () {
const renderScene = (route, navigator) => (
<View style={{flex: 1, marginTop: 20, backgroundColor: '#FFFFFF'}}>
{route.render()}
</View>
)
const renderMain = () => {
const insertAttachment = () => {
const doc = {
'title': 'with attachment',
'_attachments': {
'att.txt': {
'content_type': 'text/plain',
'data': 'TGVnZW5kYXJ5IGhlYXJ0cywgdGVhciB1cyBhbGwgYXBhcnQKTWFrZS' +
'BvdXIgZW1vdGlvbnMgYmxlZWQsIGNyeWluZyBvdXQgaW4gbmVlZA=='
}
}
}
localDB.post(doc)
.then(result => console.log('save.attachment', result))
.catch(error => console.warn('save.attachment.error', error, error.message, error.stack))
}
const insertRecords = count => {
for (let index = 0; index < count; index++) {
localDB.post({
text: `Record ${index}/${count}`
})
}
}
const destroy = count => {
localDB.destroy()
.then(() => console.log('destroyed'))
.catch(error => console.warn('destroyed', error))
}
const { dataSource } = this.state
const renderSeparator = (sectionID, rowID) => (
<View
key={rowID}
style={{borderColor: '#969A99', borderBottomWidth: StyleSheet.hairlineWidth}} />
)
const renderRow = (row) => {
const updateItem = () => {
const newRow = {...row}
newRow.clickCount = newRow.clickCount ? newRow.clickCount + 1 : 1
localDB.put(newRow)
.then(result => console.log('Updated Item', result))
.catch(error => console.warn('Error during update Item', error))
}
return (
<TouchableHighlight onPress={updateItem}>
<View key={row._id}>
<Text style={{fontWeight: 'bold'}}>{row._id}</Text>
<Text>{JSON.stringify(row, null, 4)}</Text>
</View>
</TouchableHighlight>
)
}
const renderList = () => (
<ListView
dataSource={dataSource}
renderRow={renderRow}
renderSeparator={renderSeparator}
enableEmptySections />
)
return (
<View style={{flex: 1}}>
<View>
{!!this._sync && <Text style={{fontWeight: 'bold'}}>{this.state.syncUrl}</Text>}
<Text style={{fontWeight: 'bold'}}>Count: {this.state.count}</Text>
</View>
<View
style={{borderColor: '#969A99', borderBottomWidth: StyleSheet.hairlineWidth}} />
{!dataSource
? (<Text>Loading...</Text>)
: renderList()
}
<ActionButton buttonColor='#78B55E'>
<ActionButton.Item
buttonColor='#005BFF'
title='Destroy Database'
onPress={destroy}>
<Text>destroy</Text>
</ActionButton.Item>
<ActionButton.Item
buttonColor='#005BFF'
title='Insert Attachments'
onPress={insertAttachment}>
<Text>attach</Text>
</ActionButton.Item>
<ActionButton.Item
buttonColor='#005BFF'
title='Insert 250 Records'
onPress={() => insertRecords(250)}>
<Text>insert</Text>
</ActionButton.Item>
<ActionButton.Item
buttonColor='#005BFF'
title='Sync'
onPress={() => this._navigator.push({name: 'Sync', render: renderSync})}>
<Text>sync</Text>
</ActionButton.Item>
<ActionButton.Item
buttonColor='#005BFF'
title='Add Item'
onPress={() => this._navigator.push({name: 'AddItem', render: renderAddItem})}>
<Text>+</Text>
</ActionButton.Item>
</ActionButton>
</View>
)
}
const renderButton = (text, onPress) => {
return (
<TouchableHighlight
onPress={onPress}
style={{
flexDirection: 'column',
paddingTop: 3,
paddingBottom: 3,
marginLeft: 10,
marginRight: 10,
backgroundColor: '#78B55E',
borderRadius: 5
}}>
<Text
style={{
flex: 1,
fontSize: 18,
fontWeight: 'bold',
color: '#FFFFFF',
paddingLeft: 10,
paddingRight: 10,
paddingTop: 2,
alignSelf: 'center'
}}>
{text}
</Text>
</TouchableHighlight>
)
}
const renderSync = () => {
const addSync = () => {
if (this._sync) {
this._sync.cancel()
this._sync = null
}
if (this.state.syncUrl) {
const remoteDb = new PouchDB(this.state.syncUrl, {ajax: {cache: false}})
this._sync = PouchDB.sync(localDB, remoteDb, {live: true, retry: true})
.on('error', error => console.error('Sync Error', error))
.on('change', info => console.log('Sync change', info))
.on('paused', info => console.log('Sync paused', info))
}
this._navigator.pop()
}
return (
<View style={{flex: 1}}>
<TextInput
style={{
height: 40,
lineHeight: 40,
fontSize: 16,
paddingLeft: 10,
paddingRight: 10
}}
autoFocus
keyboardType='url'
clearButtonMode='always'
placeholder='enter URL'
onChangeText={(text) => this.setState({syncUrl: text})}
value={this.state.syncUrl} />
{renderButton('Add Sync', addSync)}
</View>
)
}
const renderAddItem = () => {
const addItem = () => {
localDB.post(JSON.parse(this.state.newItem))
.then(result => {
this.setState({newItem: ''})
this._navigator.pop()
})
.catch(error => console.error('Error during create Item', error, error.message))
}
return (
<View style={{flex: 1}}>
<TextInput
style={{
height: 340,
lineHeight: 40,
fontSize: 16,
paddingLeft: 10,
paddingRight: 10
}}
autoFocus
clearButtonMode='always'
multiline
placeholder='JSON Object here'
onChangeText={(text) => this.setState({newItem: text})}
value={this.state.newItem} />
{renderButton('Add Item', addItem)}
</View>
)
}
return (
<View style={{flex: 1}}>
<Navigator
ref={navigator => { this._navigator = navigator }}
renderScene={renderScene}
initialRoute={{name: 'Main', render: renderMain}}
/>
</View>
)
}
})