I have 2 components which are CalendarList and CalendarListItem. I use Listview to displays 10 records in CalendarListItem at the first load and it will add more 10 records when user scroll down.
I meet trouble when try to update Listview containing Row and Section to append next 10 records when user scroll down to the end of list. I have searched and applied hints but most of questions relating with rows only that not work for me.
Here is my code:
constructor(props) {
super(props);
this.ds = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2,
sectionHeaderHasChanged: (s1, s2) => s1 !== s2,
});
this.state = {
eventData: [],
eventDatas: [],
dataBlob: {},
dataSource: {},
dataBlog: [],
refreshing: false,
page: 1
};
}
componentWillMount() {
this.loadEventData();
}
componentDidMount() {
this.loadEventData();
}
loadEventData() {
eventState = this.props.eventtop;
console.log('NEW DATA', eventState);
const tempDataBlob = this.state.dataBlob;
this.state.eventData = this.props.eventtop;
this.state.eventData.forEach(item => {
const event = item;
const date = new Date(item.EventDate);
const group = dateFormat(date, 'mmmm yyyy');
if (currentGroup !== group) {
currentGroup = group;
currentIndex++;
this.state.eventDatas.push({ divider: currentGroup, data: [] });
}
this.state.eventDatas[currentIndex].data.push(event);
tempDataBlob[this.state.eventDatas[currentIndex].divider] = this.state.eventDatas[currentIndex].data;
this.setState({
dataBlob: tempDataBlob
});
});
this.setState({
dataSource: this.ds.cloneWithRowsAndSections(this.state.dataBlob)
});
console.log('FUCKING DATA', this.state.dataBlob);
}
renderRow(rowData) {
return (
<TouchableOpacity
onPress={() => {
if (window.width <= 600) {
Actions.calendarDetail({ eventtop: rowData });
} else if (window.width > 600) {
this.props.getEventd(rowData);
this.passState.bind(this.props.eventItems);
}
}}
>
<View>
<Text style={styles.evenType}>
{rowData.EventType}
</Text>
<Text style={{ ...styles.contentStyle, ...styles.contenStyle2 }}>
{dateFormat(rowData.EventDate, 'mm/dd/yyyy')}
</Text>
<Icon
name='chevron-thin-right'
style={styles.iconStyle}
/>
<View
style={styles.titleStyle}
>
<Text style={styles.contentStyle}>
{rowData.Title}
</Text>
</View>
</View>
</TouchableOpacity>
);
}
renderSectionHeader(sectionData, sectionId) {
return (
<View>
<Text style={styles.timeStyle}>
{sectionId}
</Text>
</View>
);
}
render() {
return (
<ListView
style={{ flex: 1 }}
enableEmptySections
dataSource={this.state.dataSource}
renderRow={data => this.renderRow(data)}
renderSectionHeader={this.renderSectionHeader}
onEndReached={this.props.onEndReached}
renderFooter={this.props.renderFooter}
onEndReachedThreshold={30}
/>
);
}
I found a solution yesterday. Actually I need to create another Action Creator and place it inside CalendarListItem, that action will return state which is new data then I concat old data with that new data. Done!
Related
export default class AchieveScreen extends ValidationComponent{
constructor(props) {
super(props)
this.state = {
visible: false,
filter: 1,
date: new Date(),
selected: new Date(),
loaded: false,
data: [],
feedbackText:"",
target:[],
refreshing:false,
refreshValue:1
}
}
handleUpdate = async () => {
this.setState({ loaded: false })
await this.getter()
this.forceUpdate();
};
GetData = async () => {
const {date,selected}=this.state
const data = await GetAchieve()
if (data.status == 200) {
this.setState({
data: data.data,
target:data.data !== null ? data.data.filter((achieve) => achieve.date.includes(selected)) : null,
loaded: true,
})
}
}
componentDidMount() {
this._unsubscribe = this.props.navigation.addListener('focus',() => {
console.log('ok')
const UserStatus=this.status()
if(UserStatus){
this.GetData()
}
});
}
_onRefresh=async()=> {
try {
this.setState({refreshing: true});
this.setState(({ refreshValue }) => ({
refreshValue: refreshValue + 1,
}));
this.setState({refreshing: false});
} catch (error) {
throw error
}
}
componentWillUnmount() {
this._unsubscribe();
}
shouldComponentUpdate(nextProps, nextState) {
if(this.state.data != nextState.data){
console.log('data re')
return true;
}
if(this.state.refreshValue != nextState.refreshValue || this.state.selected != nextState.selected || this.state.target != nextState.target ){
console.log('refreshing value')
return true;
}
return false
}
sendFeedBack=async()=>{
const {feedbackText} = this.state
this.validate({
feedbackText: {minlength:3, maxlength:4000},
});
if(!this.isFieldInError('feedbackText')){
const request = await feedback(feedbackText)
if(request.status == 200){
this.setState({
feedbackText:"",
visible:false
})
}
}
}
flag = (date) => {
items = this.state.data !== null ? this.state.data.filter((achieve) => achieve.date.includes(date)) : null
let Professional = false
let Personal = false
if (!!items) {
items.map(item => {
if (item.flag == 1) { Professional = true } else if (item.flag == 2) { Personal = true }
})
if (Professional && Personal) {
return <>
<Text> <Icon name="flag-o" size={10} color="#ff6666" /> </Text>
<Text> <Icon name="star-o" size={10} color="#cc80ff" /> </Text>
</>
} else if (Professional) {
return <Text> <Icon name="flag-o" size={10} color="#ff6666" /> </Text>
} else if (Personal) {
return <Text> <Icon name="star-o" size={10} color="#cc80ff" /> </Text>
}
}
}
week = () => {
const { date, selected,loaded } = this.state
const week = this.state.date.week()
if(loaded){
return (
<>
{week.map((day, index) => {
return (
selected === week[index].plenaDiem ?
<LinearGradient key={index} colors={['#EBDDFD', '#DFDCFF']} start={[0, 1]} end={[1, 0]} style={{ borderRadius: 12 }}>
<TouchableOpacity
key={index}
style={[styles.weekday]}
onPress={() => { this.setState({ selected: week[index].plenaDiem }) }}
disabled={week[index].enable}
>
<Text style={styles.name} >{week[index].dies}</Text>
<Text style={[styles.num, { color: week[index].color }]} >{week[index].diem}</Text>
<View style={styles.flags}>
{this.flag(week[index].plenaDiem)}
</View>
</TouchableOpacity>
</LinearGradient>
:
<TouchableOpacity
key={index}
style={[styles.weekday]}
onPress={() => {
console.log(this.state.target)
this.setState({
selected: week[index].plenaDiem,
target:this.state.data !== null ? this.state.data.filter((achieve) => achieve.date.includes(week[index].plenaDiem)) : null,
})
}}
disabled={week[index].enable}
>
<Text style={styles.name} >{week[index].dies}</Text>
<Text style={[styles.num, { color: week[index].color }]} >
{week[index].diem}
</Text>
<View style={styles.flags}>
{this.flag(week[index].plenaDiem)}
</View>
</TouchableOpacity>
)
})
}
</>
)
}
}
render() {
const { data, date, visible, selected, filter, loaded,feedbackText,refreshing,target } = this.state
// let render = data !== null ? data.filter((achieve) => achieve.date.includes(selected)) : null
// if (filter !== 3 && render !== null) {
// render = render.filter((item) => item.flag == filter)
// }
return (
<>
<View style={styles.header} >
<View style={styles.top}>
<View style={styles.icon}>
<Image source={require('../../assets/header/CalendarIcon.png')} />
<Text style={styles.day}>{date.day()}</Text>
</View>
<View style={styles.items}><Image source={require('../../assets/header/medalLogo.png')} /></View>
<View style={styles.items}><IconButton icon='question' style={styles.question} color={"#000"} size={16} onPress={() => this.setState({ visible: true })} /></View>
</View>
<Modal
visible={visible}
backdropStyle={styles.backdrop}
onBackdropPress={() => this.setState({ visible: false })}>
<Card disabled={true} style={{backgroundColor:"#FFF",width:wp('90%'),borderRadius:10}}>
<Input
name='feedbackText'
value={feedbackText}
style={styles.feedbackText}
multiline={true}
maxLength={4000}
placeholder="tell us about you expermenit"
onChangeText={(text) => { this.setState({
feedbackText: text,
}) }}
/>
<Button
disabled={feedbackText.length<3?true:false}
onPress={() => {this.sendFeedBack()}}>
subimt
</Button>
</Card>
<View style={[styles.close]}>
<AntDesign name={"closecircleo"} color="#000" onPress={() => this.setState({ visible: false })} size={25} />
</View>
</Modal>
<ScrollView
contentContainerStyle={styles.scrollView}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={this._onRefresh.bind(this)}
/>
}
>
<View style={styles.month}>
<Text style={styles.monthName}>{date.monthName()}</Text>
</View>
<View style={styles.week}>
{loaded ? this.week() : <LoadingScreen/>}
</View>
</ScrollView>
</View>
<View style={styles.container} >
<View style={styles.achieve}>
<View>
{/* <SwitchSelector
options={options}
initial={0}
style={styles.switch}
buttonColor={"#fff"}
textColor={"#AB9CB3"}
selectedColor={"#000"}
buttonMargin={3}
imageStyle={styles.switchicon}
backgroundColor={"#F0F1F8"}
onPress={value => this.setState({ filter: value })}
/> */}
</View>
<View style={styles.count}>
<Text style={styles.countText}>you have achieved {target !== null ? target.length : null}</Text>
</View>
</View>
<View style={styles.cards}>
<Cards type={true} data={target} storage={data} handle={this.handleUpdate} />
</View>
</View>
</>
)
}
}
this is calendar component when run it no thing to display but data can be in console log. i can show data there, I need to hit Ctrl+s to refresh expo 'fast refresh' to show data in simulator
I have load Logic in render section but issue is still need fix
any suggestions?
this screen before hit Ctrl+s data is already in state but not rendering "first run"
here after hit Ctrl+s to refresh screen to show data
I created a function to view cart details below every screen when a user add a item to cart and when user remove function cart details will hide again, but when I remove item from cart, cart details not hidding, can someone tell me what's wrong, below is my code
reducer
if (action.type === SHOW_CART) {
let addedItem = state.addedItems;
if (addedItem === 0) {
console.log(addedItem);
return {
...state,
show: state.showCart,
};
}
}
const initialstate = {
showChart: false,
addedItems: [],
}
It's my redux code where I'm performing that function, addItems is my cart which is blank array
action
export const showCart = (id) => {
return {
type: SHOW_CART,
showCart: true,
id,
};
};
Here is my action
ViewCart
{this.props.show ? (
<View style={styles.total}>
<Text style={styles.totaltext}>Total:</Text>
<Text style={styles.priceTotal}>{this.props.total}</Text>
<View style={styles.onPress}>
<Text
style={styles.pressText}
onPress={() => RootNavigation.navigate("Cart")}
>
View Cart
</Text>
</View>
</View>
) : null}
Here is my view cart detail where I showing cart details when user add item to cart
can someone please help
You should compare the length, you are currently comparing the array directly so it would also go to the false path, so change that first.
if (action.type === SHOW_CART) {
let addedItem = state.addedItems;
if (addedItem.length === 0) {
console.log(addedItem);
return {
...state,
show: state.showCart,
};
} else {
return {
...state,
show: action.showCart,
};
}
}
In view cart,
{this.props.show && this.props.items.length >0 ? (
<View style={styles.total}>
<Text style={styles.totaltext}>Total:</Text>
<Text style={styles.priceTotal}>{this.props.total}</Text>
<View style={styles.onPress}>
<Text
style={styles.pressText}
onPress={() => RootNavigation.navigate("Cart")}
>
View Cart
</Text>
</View>
</View>
) : null}
const mapStateToProps = (state) => {
return {
total: state.clothes.total,
show: state.clothes.show,
items: state.clothes.addedItems,
};
};
I have two functions that are not rendering: renderTeachers() and renderSubjects(). They render based on the length of the teachers array in the state object. I console logged state.teachers and the result is as expected, the array length is more than one, but the functions still don't render. I don't understand why these functions are not rendering.
class Search extends Component {
state = {
teachers: [],
subjects: [],
rating: 3.5,
};
requestData = (queryObj) => {
console.log(queryObj);
const client = algoliasearch('__ID__', '__KEY__');
const queries = [{
indexName: 'teachers',
query: queryObj,
filters: 'Rating >= 3.5',
}, {
indexName: 'subjects',
query: queryObj,
}];
if (queryObj === '') {
this.setState({ showSearchVal: false });
} else {
client.search(queries, this.searchCallback.bind(this));
}
}
searchCallback = (err, content) => {
if (err) {
console.error(err);
return;
}
this.setState({ teachers: content.results[0].hits, subjects: content.results[1].hits });
}
renderSubjects = () => {
if (this.state.subjects.length >= 1) {
return this.state.subjects.map(subject => <SubjectDetail key={subject.objectID} subject={subject} />);
}
return null;
}
renderTeachers = () => {
console.log('in');
if (this.state.teachers.length >= 1) {
return this.state.teachers.map(teacher => <SearchDetail key={teacher.UID} person={teacher} />);
}
return null;
}
render() {
return (
<View>
<Header search onPress={() => this.searchBar.show()} />
<SearchBar
backgroundColor='#02254e'
iconColor='#4f5d6d'
placeholderTextColor='#4f5d6d'
backButton={<Icon name='keyboard-backspace' size={24} color='#4f5d6d' style={{ alignSelf: 'center' }} />}
textColor='white'
animate={false}
handleChangeText={this.requestData}
selectionColor='#01152d'
fontFamily='avenir_heavy'
backCloseSize={24}
ref={(ref) => { this.searchBar = ref; }}
/>
<View style={{ width, height, alignItems: 'center', flex: 1 }}>
<ScrollView style={{ flex: 1 }}>
<Text style={styles.topResultTextStyle}>
{this.state.subjects.length >= 1 ? 'Subjects' : ''}
</Text>
{this.renderSubjects()}
<Text style={styles.topResultTextStyle}>
{this.state.teachers.length >= 1 ? 'Teachers' : ''}
</Text>
{this.renderTeachers()}
</ScrollView>
</View>
</View>
);
}
}
export { Search };
from the code you post, I can't see a reason why teachers / subjects won't render. My question is, how do you set the teachers /subjects arrays ? without changing state / props, react component shouldn't render. Can you please share the arrays set code ?
I'm trying to create a todo list, then I'm trying to use this checkbox package
react-native-check-box
I don't know if this issue come from that package
when I click the checkbox and click the delete button this is what happen
And here is my code for displaying the list
interface TodoProps{
todo: TodoModel;
ter:string;
}
interface TodoState{
dataSource: any;
myTodo: Array<ITodo>;
}
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => true});
export default class Todo extends React.Component <TodoProps,TodoState>{
constructor(props:TodoProps) {
super(props);
this.state = {
dataSource: ds.cloneWithRows([]), // or put your initial data here
myTodo: []
};
}
componentWillReceiveProps = (nextProps) => {
console.log(this.state.myTodo);
let data = {
title: nextProps.ter,
isChecked: false
};
let todoList = this.state.myTodo;
if (nextProps.ter) {
todoList.push(data);
}
this.setState({
myTodo: todoList
});
}
onDelete(){
let todos = this.state.myTodo.filter((todo:ITodo) => {
return !todo.isChecked;
});
this.setState({
myTodo: todos
});
}
render() {
let dataSource = this.state.dataSource.cloneWithRows(this.state.myTodo);
return (
<View style={styles.container}>
<View style={styles.box2}>
<ListView enableEmptySections={true} dataSource={dataSource} renderRow={(rowData, sectionID, rowID) => <TodoList data={rowData} onClick={this.onClick.bind(this)} id={rowID} /> } />
</View>
<View style={styles.box3}>
<TouchableOpacity style={styles.bbox1} onPress={()=> alert('weee')}>
<Text style={styles.tabText}>All</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.bbox2} onPress={()=> alert('weee')}>
<Text style={styles.tabText}>Complete</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.bbox3} onPress={()=> alert('weee')}>
<Text style={styles.tabText}>InComplete</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.bbox4} onPress={()=> this.onDestroy()}>
<Text style={styles.tabText}>Delete</Text>
</TouchableOpacity>
</View>
</View>
)
}
}
But if I console log the data. I find all isChecke: to false. Only the view of checkbox is not working. Do I need to use componentwillamount() for this?
Use the below sample code
_onRefresh() {
this.setState({refreshing: true});
// your callback function or call this.componentDidMount()
}
render() {
return (
<ListView
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this._onRefresh.bind(this)}
/>
}
...
>
...
</ListView>
);
}
I am having strange behavior when a row is being added to my listview. I am not sure where my logic is wrong. I have tabs using react-native-tab-view. On Tab 2 I am adding a object to "Favorites" array that has is being displayed on Tab 4. Before I add the object this is what is being displayed
After I add the object and go back to Tab 4 this is what I am see
And Code
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2})
constructor(props) {
super(props)
this.state = {
favoriteDB: props.favorites,
renderPlaceholder: true,
dataSource: ds.cloneWithRows([])
}
}
componentDidMount() {
InteractionManager.runAfterInteractions(() => {
this.setState({
dataSource: ds.cloneWithRows(this.state.favoriteDB),
renderPlaceholder: false
})
})
}
componentWillReceiveProps(prevProps) {
const {favorites} = this.props
if (JSON.stringify(favorites) != JSON.stringify(prevProps.favorites)) {
this._updateFavorites()
}
}
_updateFavorites() {
const {favorites} = this.props
this.setState({
favoriteDB: favorites,
dataSource: ds.cloneWithRows(favorites)
})
}
render() {
const {dataSource} = this.state
const {visibleHeight, visibleWidth} = this.props
if (this.state.renderPlaceholder)
return <Placeholder/>
return (
<Container theme={theme}>
<View style={{ flex:1, height: visibleHeight - 100, width: visibleWidth }}>
<Row>
<Col>
<List>
<ListView
style={{ height: visibleHeight - 100, width: visibleWidth }}
enableEmptySections={TRUE}
automaticallyAdjustContentInsets={FALSE}
initialListSize={100}
pageSize={100}
dataSource={dataSource}
renderRow={rowData => this._renderRow(rowData)}/>
</List>
</Col>
</Row>
</View>
</Container>
)
}
I experienced this adding and removing rows to the input of cloneWithRows with ListView as well as the data array for the new SectionList.
My workaround is to add a key for ListView that changes when the dataSource changes (name and size worked).
return (
<SectionList
key={"mylistview_" + this.props.maps.length}
style=
...
See https://stackoverflow.com/a/31481960/7223