I am switching from android to react native. Complete naive.
I wanted to implement something like recyclerview in react native and found out about FLATLIST
Now the problem is initially my data variable is empty and later on i am adding data into that variable. Now how do i notify the flat list that the data has changed and it should now re render itself.
Like in recyclerview we use adapter.notifyDataSetChanged(); to inform the recycler view about the change that it should re-render itself now
The code i am using is
export default class Convo extends Component{
constructor(props){
super(props);
this.state = {
loggedIn: 'false',
title: 'Login/SignUp',
messages: []
};
this.downloadConversation = this.downloadConversation.bind(this);
}
componentDidMount(){
this.downloadConversation();
}
downloadConversation(){
this.setState(
{message: [
{
key: "HIHI",
name: "lets this bullshit",
message: "I i i"
},
{
key: "HIHI2",
name: "lets change bullshit",
message: "I i i"
},
{
key: "HIHI3",
name: "lets change this ",
message: "I i i"
}
]}
);
//After updating the messages object, i want to notify flat list about
//the change, basically i will be updating this object asynchronously
// in background which will take time. for now i am updating directly
//to show you
}
renderFlatListItem(item) {
return (
<View key={item.key} style={styles1.flatviewItem}>
<Text>User1</Text>
<Text style={styles1.name}>{item.name}</Text>
<Text style={styles1.messageStyle}>{item.message}</Text>
</View>
)
}
render(){
return(
<View style={styles1.container}>
<View style={styles1.header}>
<Text style={styles1.h2style}>Conversation List</Text>
</View>
<FlatList
style={styles1.flatview}
extraData={this.state}
keyExtractor={item=>item.key}
showsVerticalScrollIndicator={true}
data={this.state.messages}
renderItem={({item}) => this.renderFlatListItem(item)}
/>
</View>
);
}
}
Your component should automatically re-render when the component state changes (if anything in your render method references the changed piece of state). I think you just need to change 'message' to 'messages' when you setState in your downloadConversation() method. Your FlatList is looking for this.state.messages, not this.state.message and this.state.messages is never changed. Just fix that typo & hopefully that fixes it.
Related
Unable to display the text entered in the Eventform and show it on the flatlist of EventList page.I am new to react native just need some help to solve the problem. Learning to develop a notes application.
EventForm js I am entering the text in it which has name location and notes field but when press add button does not showing it in the flatlist.
class EventForm extends Component {
state = {
title: null,
date: '',
};
handleAddPress = () => {
saveevents(this.state)
// console.log('saving events:', this.state);
.then(()=> this.props.navigation.goBack());
}
// handlePress() {
// this.props.onBtnPress()
// }
// }
handleChangeTitle = (text) => {
this.setState({ title: text });
}
handleChangeLocation =(text) => {
this.setState({location: text});
}
render() {
return (
<View
style={{
flex: 1
}}
>
<View style={styles.fieldContainer}>
<TextInput
style={styles.text}
placeholder="Name"
spellCheck={false}
value={this.state.title}
onChangeText={this.handleChangeTitle}
/>
<TextInput
style={styles.text}
placeholder="Enter your Location"
spellCheck={false}
value={this.state.location}
onChangeText={this.handleChangeLocation}
/>
<AutoExpandingTextInput
placeholder="Write your Notes here"
spellCheck={false}
style={[styles.default, {height: Math.max(35, this.state.height)}]}
value={this.state.text}
/>
</View>
<TouchableHighlight
onPress ={() =>this.handleAddPress.bind(this)}
// onPress={this.handleAddPress}
style={styles.button}
>
<Text style={styles.buttonText}>Add</Text>
</TouchableHighlight>
</View>
EventList js where I would like to display the dynamic text entered in EventForm should appear in flatlist. I am saving the flatlist content in db json file and calling it in the EventList.
const styles = StyleSheet.create({
list: {
flex: 1,
paddingTop: 20,
backgroundColor: '#A9A9A9'
},
});
class EventList extends Component {
state = {
events: [],
}
componentDidMount() {
//getEvents().then(events => this.setState({ events }));
const events = require('./db.json').events;
this.setState({ events });
}
render() {
return [
<FlatList
key="flatlist"
style={styles.list}
data={this.state.events}
renderItem={({ item, seperators }) => (<EventCard events=
{item} />)}
keyExtractor={(item, index) => index.toString()}
/>,
My db json file is this which I have manually entered the details.Data that is dynamically entered have to save in db json file and should reflect in the flatlist.
{
"events":[
{
"name":"chandu",
"date":"15-06-2018 ",
"location":"Sydney",
"content":"How are you..?",
"id":"05dafc66-bd91-43a0-a752-4dc40f039144"
},
{
"name":"bread",
"date":"15-07-2018 ",
"location":"Sydney",
"content":"I bought bread..?",
"id":"05dafc66-bd91-43a0-a752-4dc40f039145"
}
]
}
I am expecting whatever the text that is entered in the form should save and show me on the Flatlist which is in EventList file. Please help if you get any solution for it.
I have added alert message when onPressed to show that whether it is pressed or not.
I am expecting whatever the text that is entered in the form should save and show me on the Flatlist which is in EventList file. Please help if you get any solution for it.
I have added alert message when onPressed to show that whether it is pressed or not.
Your EventForm and EventList are two separate component without any shared props.
Assuming you are updating db.json file (using file read/write methods) from EventsForm component, still in the EventsList the data is fetched only once on componentDidMount.
You will need to pass the data for EventList as props or keep in state. If you keep it in props, then you must update the value of state using some life cycle method such as getDerivedStateFromProps props or something similar.
Edit:
I would suggest using global state management library like redux, for saving your data entered in the EventForm component, instead of read/write in a file.
You can save the data by dispatching an action in your EventForm component.
Later access that data in you EventList component using
this.props.your_db_name
You can save this data even on app kill using redux-persist
If you still want to continue with file read/write, you can look at this library react-native-fs
I am trying to toggle ios Switch in react native. But the switch comes back to initial position as soon as I change it.
What I have:
class ABC extends Component {
constructor(props) {
super(props)
this.state = {
obj: []
}
}
fetch(){
// fetch something from remote server, set it to state object array
}
setStatus(id, value){
var temp = [...this.state.obj]
temp.map((t) => {
if (t.id == id) {
t.flag = value
}
})
this.setState({ obj: temp })
}
render() {
return (
<View>
<FlatList
data={this.state.obj}
renderItem={({ item }) =>
<View>
<Text>{item.name}</Text>
<Switch
onValueChange={(val) => this.setStatus(item.id, val)}
value={item.flag}
/>
</View>
}
keyExtractor={({ id }, index) => id.toString()}
/>
</View>
);
}
}
I logged the before and after value of obj state and they seem to update. Should the FlatList be rendered again (like a web page refresh) ? Or is there something I am missing ? Searched SO for answers, couldn't find my mistake.
Flatlist has a prop called extraData.
This prop tells Flatlist whether to re-render or not.
If data in extraData changes then flatlist re-renders based on new data provided in data prop.
So whenever you need to re-render flatlist just change something in extraData.
Best way is to pass state toextraData which is passed to Data.
So, just pass extraData={this.state.obj}.
there also other way called forceUpdate.
you can call this.forceUpdate().
but this is not recommended because this will render not only flatlist but entire component in which you are calling this.
I'm trying to call a function that will fire upon onFoucs on TextInput that will scroll the scrollView all the way down (using scrollToEnd())
so this is my class component
class MyCMP extends Component {
constructor(props) {
super(props);
this.onInputFocus = this.onInputFocus.bind(this);
}
onInputFocus() {
setTimeout(() => {
this.refs.scroll.scrollToEnd();
console.log('done scrolling');
}, 1);
}
render() {
return (
<View>
<ScrollView ref="scroll">
{ /* items */ }
</ScrollView>
<TextInput onFocus={this.onInputFocus} />
</View>
);
}
}
export default MyCMP;
the component above works and it does scroll but it takes a lot of time ... I'm using setTimeout because without it its just going down the screen without calculating the keybaord's height so it not scrolling down enough, even when I keep typing (and triggering that focus on the input) it still doesn't scroll all the way down.
I'm dealing with it some good hours now, I did set the windowSoftInputMode to adjustResize and I did went through some modules like react-native-keyboard-aware-scroll-view or react-native-auto-scroll but none of them really does the work as I need it.
any direction how to make it done the right way would be really appreciated. thanks!
Rather than using a setTimeout you use Keyboard API of react-native. You add an event listener for keyboard show and then scroll the view to end. You might need to create some logic on which input is focused if you have more than one input in your component but if you only have one you can just do it like the example below.
Another good thing to do is changing your refs to functional ones since string refs are considered as legacy and will be removed in future releases of react. More info here.
class MyCMP extends Component {
constructor(props) {
super(props);
this.scroll = null;
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow.bind(this));
}
componentWillUnmount () {
this.keyboardDidShowListener.remove();
}
_keyboardDidShow() {
this.scroll.scrollToEnd();
}
render() {
return (
<View>
<ScrollView ref={(scroll) => {this.scroll = scroll;}}>
{ /* items */ }
</ScrollView>
<TextInput />
</View>
);
}
}
export default MyCMP;
If you have a large dataset React Native docs is telling you to go with FlatList.
To get it to scroll to bottom this is what worked for me
<FlatList
ref={ref => (this.scrollView = ref)}
onContentSizeChange={() => {
this.scrollView.scrollToEnd({ animated: true, index: -1 }, 200);
}}
/>
How to get the Id of the element in onPress event handler.
I am adding elements dynamically and wants to know in the event handler of onPress of these elements to store in the state which elements are clicked.
Here is the code i have
export default class App extends Component {
constructor(props){
super(props);
this.getElements= this.getElements.bind(this);
this.selectElement = this.selectElement.bind(this);
}
componentWillMount(){
this.state = {
noOfElements :10
}
}
selectElement(e,key){
console.log('selectElement() : key=',key);
}
getElements(){
let elements =[];
for(let index=0;index<this.state.noOfElements;index++){
elements.push(
<View key={'View_'+index} style={{flex:1}}>
<Button
key={'View_'+index}
id={index}
onPress={(e,index) => {this.selectElement(e,index)}}
title={'Button-'+index}
/>
</View>
);
}
return elements;
}
render(){
let elements = this.getElements();
return(
<View style={styles.container}>
<Text>Test</Text>
{elements}
</View>
);
}
}
I tried just passing the key like
onPress={(index) => {this.selectElement(index)}}
with no success..
Not sure what i am doing wrong.
The way you have it, i think index would come up undefined, just remove index as an argument in your onPress so it grabs index from the for loop. Also you can prob refactor it using map.
onPress={(e) => this.selectElement(e,index)}
Changed the event handler as below and it is working fine now.
onPress={this.selectElement.bind(this,index)}
and the function now just accepts the index
selectElement(key){
console.log('selectElement() : Index=',key);
}
I've trying to set up a change event if someone modifies a switch component. The approach is to design a view that contains multiple switches and allows the user to set the state per each notification that will end up in a POST api-call. Futher, I'd like to load the initial values from a api-call.
How can I access the state (weather it's checked / unchecked) in my onChangeFunction? And how can I get an element using their ID or name? (same as in HTML/CSS with #mySwitch.setValue(true)?
Given code:
class Settings extends Component {
onChangeFunction(type, props) {
Alert.alert("changed", "==> " + props.state)
}
render() {
return (
<View style={styles.container}>
<Switch onValueChange={this.onChangeFunction.bind(this, "TASK_CREATED", this.props)} value={this.state} />
</View>
);
}
}
You have a mess there between the propsand the state concept. You can do:
class Settings extends Component {
state = {
taskCreated: false,
};
onChangeFunction(newState) {
this.setState(newState, () => Alert.alert("Changed", "==> " + this.state));
}
render() {
return (
<View style={styles.container}>
<Switch onValueChange={(value) => this.onChangeFunction({taskCreated: value})}
value={this.state.taskCreated}
/>
</View>
);
}
}
Notice that this.setState is asynchronous so you can safely read its value using the callback that the method provides.