I have a parent class that passes a function called editClassInfo
to a child class. This function, is bound to the parent, and when called, immutably changes the state of the parent. However, the parent does not render again, instead having to set the state from within the parent.
Specifically, the problem is with a modal component that has a textInput
that, when the text is changed, sets the state of the parent screen. However, when the modal is closed, the screen's state does not update immediately, even though the state is changed. Instead, another this.setState()
has to be called in order for the render to happen again.
Here is a picture reference of the problem: https://i.stack.imgur.com/cH6yy.jpg
Here is the code:
This is the parent component.
export default class Classes extends Component {
static navigationOptions = {
title: 'Classes'
};
constructor() {
super();
this.state = {
numObjects: 3.,
classes: [
{
className: "Math",
teacherName: "Someone",
},
{
className: "Science",
teacherName: "Someone",
},
{
className: "Art",
teacherName: "Someone",
}
]
};
this.editClassInfo = this.editClassInfo.bind(this);
}
editClassInfo(index, infoType, value) {
let newClass = this.state.classes;
switch (infoType) {
case 'className':
newClass[index].className = value;
break;
case 'teacherName':
newClass[index].teacherName = value;
break;
}
this.setState({classes: newClass});
}
addClass(name, name2) {
let newClass = this.state.classes.concat({className: name, teacherName: name2});
this.setState({classes: newClass});
}
loadClasses = () => {
this.setState({
numObjects: this.state.numObjects * 2,
})
}
render(){
const classData = this.state.classes;
console.log(this.state.classes[0]);
return (
<View style={styles.container}>
<TopBar title='Classes'/>
<View style={styles.classHeader}>
<Text style={styles.currentClasses}> CURRENT CLASSES </Text>
<TouchableOpacity onPress={() => {this.addClass('World History', 'Someone')}}>
<Image
style = {styles.addClass}
source={require('../resources/addClass.png')}
/>
</TouchableOpacity>
</View>
<FlatList
data = { classData }
onEndReached = {this.loadClasses}
keyExtractor = {(item, index) => index.toString()}
initialNumtoRender = {3}
renderItem = {({item}) =>
<ClassBox
index={this.state.classes.indexOf(item)}
editClassInfo ={this.editClassInfo}
className={item.className}
teacherName={item.teacherName}
/>
}
/>
</View>
);
}
}
I pass editClassInfo
onto a component called ClassBox
:
export default class ClassBox extends Component {
static propTypes = {
className: PropTypes.string.isRequired,
teacherName: PropTypes.string.isRequired,
index: PropTypes.number.isRequired
};
constructor(props) {
super(props);
this.state = {
isVisible: false,
};
this.modalVisible = this.modalVisible.bind(this);
}
modalVisible(visible) {
this.setState({isVisible: visible});
}
render(){
return(
<View>
<ClassEdit
index={this.props.index}
editClassInfo={this.props.editClassInfo}
isVisible={this.state.isVisible}
modalClose={this.modalVisible}
className={this.props.className}
teacherName={this.props.teacherName}
/>
<TouchableOpacity onPress={() => {this.modalVisible(true)}}>
<View style={styles.container}>
<Image
source={{uri: 'http://via.placeholder.com/50x50'}}
style={styles.classImage}
/>
<View style={styles.classInfo}>
<Text style={styles.className}>
{this.props.className}
</Text>
<Text style={styles.teacherName}>
{this.props.teacherName}
</Text>
</View>
</View>
</TouchableOpacity>
</View>
)
}
}
This component contains the Child Modal ClassEdit
:
export default class ClassEdit extends Component {
static propTypes = {
index: PropTypes.number.isRequired,
isVisible: PropTypes.bool.isRequired,
className: PropTypes.string.isRequired,
teacherName: PropTypes.string.isRequired
}
render() {
return(
<Modal
animationType="none"
transparent={false}
visible={this.props.isVisible}
>
<View style={styles.container}>
<View style={styles.closeTop}>
<TouchableOpacity onPress={() => {
this.props.modalClose(false);
}}>
<Image
style={styles.closeIcon}
source={require('../resources/close.png')}
/>
</TouchableOpacity>
</View>
<View style={styles.classInfo}>
<Image
source={{uri: 'http://via.placeholder.com/150x150'}}
style={styles.classImage}
/>
<TextInput
style={styles.className}
placeholder='Class Name'
value={this.props.className}
onChangeText = {(className) => {this.props.editClassInfo(this.props.index, 'className', className)}}
/>
<TextInput
style={styles.teacherName}
placeholder='Teacher Name'
value={this.props.teacherName}
onChangeText = {(teacherName) => {this.props.editClassInfo(this.props.index, 'teacherName', teacherName)}}
/>
</View>
</View>
</Modal>
);
}
}
It is in this last component called ClassEdit
where the parent state gets changed, but when the modal is closed, the updated state is not seen, instead having to call addClass
to trigger it.
I am a bit new to react-native so my code might not be the best, and the problem might be really simple, but any help would be appreciated.