I am using a list with a data array. I want the icon to change when the playstate changes, which if I log playState out to the console I can see it updating correctly but the icon is not responding to the change. Thanks in advance!
render() {
const playState = this.state.playState === 'playing' ? 'pause' : 'play'
return (
<Container>
<Header>
<Title>Note To Self</Title>
</Header>
<Content>
<List>
<List dataArray={this.state.storedRecordings.reverse()}
renderRow={(item) =>
<ListItem icon>
<Left>
<Icon name="trash" onPress={() => this._deleteRecording(item[1]) } />
<Icon name={playState} onPress={() => this._play(item[2]) } />
</Left>
<Body>
<Text>{item[0]}</Text>
</Body>
<Right>
<Icon name="share" onPress={() => this._upload(item) } />
</Right>
</ListItem>
}>
</List>
</List>
</Content>
{this._renderRecorderButton()}
</Container>
)
}
}
I have the same issue too.
We are looking into this
@SupriyaKalghatgi any updates on this? Would love to get it working. Thanks!
Hey @jennykortina, I believe this look a while. Actually we tried to implement this using ListView of React Native. I encountered the same problem.
Here is the code to replicate this.
import React, { Component } from "react";
import {
AppRegistry,
StyleSheet,
View,
FlatList,
TouchableOpacity,
ListView,
Text
} from "react-native";
import Icon from "react-native-vector-icons/FontAwesome";
const ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
});
export default class NBTestApp extends Component {
constructor() {
super();
this.state = {
dataSource: ds.cloneWithRows(["row 1", "row 2", "row3", "row4", "row5"]),
playState: "pause"
};
}
render() {
return (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center",
paddingTop: 40
}}
>
<ListView
style={{ height: 400 }}
dataSource={this.state.dataSource}
renderRow={rowData => {
return (
<View
style={{
flex: 1,
flexDirection: "row",
margin: 10,
padding: 10
}}
>
<Text>{rowData}</Text>
<Icon
style={{ alignSelf: "center", marginLeft: 10 }}
name={this.state.playState}
/>
</View>
);
}}
/>
<TouchableOpacity
style={{
height: 100,
width: 200,
backgroundColor: "green",
marginBottom: 40,
justifyContent: "center",
alignItems: "center"
}}
onPress={() =>
this.setState({
playState: this.state.playState === "play" ? "pause" : "play",
dataSource: ds.cloneWithRows(["row 2", "row3", "row4", "row5"])
})}
>
<Icon name={this.state.playState} size={40} />
</TouchableOpacity>
</View>
);
}
}
AppRegistry.registerComponent("NBTestApp", () => NBTestApp);
It should look something like this
As a workaround you could include your playstate variable as part of the data that goes to the List component, like dataSource: ds.cloneWithRows([{name: "row 1", playState: "play"}, {name: "row 2", playState: "pause"}]). Now it must re-render.
@Jasbir23 @SupriyaKalghatgi this doesn't actually close the ticket. It doesn't do what I want...the play button items in the list should toggle independently of one another and I want to use native kit to render the list...
@jennykortina Did you by chance get this to work? My icon is also not rendering. It renders when its not in the list but doesnt render when its added to each item in the list.
Hey @jennykortina @mgit7 , In the above code i used React Native's ListView to tackle the problem however the problem seems to exist there as well. This is more likely to be an issue with React Native. You could use the workaround i suggested to get things going for now.
You have the same object reference and thats why the row is not re-rendered since obj1 === obj2.
Once the state is mutated, create a new object:
obj1 = {...obj1, ...{ newProp: value }};
Well I thought dataSource is deprecated since the introduction of FlatList etc. by react-native. Besides dataSource isnt even mentioned in the NB docs under the list component. The tutorial for the dynamic list is avoiding this problem neatly by having the conditional which is based on this.state.loading, which I assume triggers the list component to re-render completely once loading: true -> false thus reload -> true -> false thus reload. What implications this has for the state of the underlying components such as ListItem I dont know.
I fixed this problem, currently, without checking for any side-effects or bugs as follows.
Having the list.map(...) inside the <List /> component seems to trigger a re-rendering on state change. I induce the state change via MobX here, but it should also work with native state.
I got the inspiration from here: https://medium.com/react-native-training/react-native-with-mobx-getting-started-ba7e18d8ff44
@inject("taskStore") @observer
export default class MyComponent extends Component {
componentWillMount() {
this.props.taskStore.listenForData();
}
componentDidMount() {
console.log("did mount");
}
render(): React$Element<*> {
const {navigation} = this.props.navigation;
const tasks = this.props.taskStore.getTasks;
return <BaseContainer title={"Base"} {...{navigation}} scrollable>
<List>{tasks.map((entry, i) => {
return <Task
date="2015-05-08 08:30"
title={entry.name}
subtitle={entry.description}
completed={false}
/>;
})}
</List>
</BaseContainer>;
}
}
hi , I didn't get a chance to completely understand what you gonna do but I have got through this kind of thing so I thought may be it can help you with little bit tweaking...
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
TextInput,
TouchableOpacity,
ListView,
Button
} from 'react-native';
const data = [
{ 'id': 0, 'course': 'English' },
{ 'id': 0, 'course': 'Java' },
{ 'id': 0, 'course': 'DB' },
{ 'id': 0, 'course': 'React' },
{ 'id': 0, 'course': 'Desgining' },
{ 'id': 0, 'course': 'IOS' }
]
class Row extends Component {
state = {
isSelected: false
}
render() {
return (
<TouchableOpacity onPress={() => {
this.setState({ isSelected: !this.state.isSelected })
this.props.onPress({
course: this.props.course,
isSelected: !this.state.isSelected
})
}}
style={[{ flex: 1, alignSelf: 'center', marginVertical: 2 }, this.state.isSelected ? { backgroundColor: 'orange' } : { backgroundColor: 'transparent' }]}>
<Text style={{ marginVertical: 5 }}>{this.props.course}</Text>
</TouchableOpacity>
);
}
}
export default class RNTest extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
this.state = {
DataSource: ds.cloneWithRows(data)
}
}
renderRow(row) {
return (
<Row
onPress={(obj) => alert(JSON.stringify(obj))}
course={row.course}
/>
);
}
render() {
return (
<ListView
dataSource={this.state.DataSource}
renderRow={(row) => this.renderRow(row)}
/>
)
}
}
AppRegistry.registerComponent('RNTest', () => RNTest);
@java-developer188 Was your comment directed at me?
Because the Documentation states ListView including DataSource as deprecated: https://facebook.github.io/react-native/docs/listview.html
@daemonfire300 no not at all,even i didnt read the thread completely , i was stuck in a issue which i thought not sure related to this thread so i thought may be some one make use of it and i can help in such a way,as this issue was not closed at tht time...and yes i m aware it is deprecated but due to reasons i have to stick to RN0.44 and i just solve it using all deprecated stuff
i used this approach and rows will be re-rendered
`
let items = [...this.state.items];
for(let i in items){
items[i] = Object.assign({}, items[i], {
_width: width
});
}
this.setState({
items: items
});
`
@Knight1988 Yup. That did the trick for me.
Most helpful comment
i used this approach and rows will be re-rendered
`
let items = [...this.state.items];
`