RN JS 연습 - 3
아마 지금까지의 연습을 보면서 bind
라는 부분에 대해 이해가 안되는 사람들이 많았을 것이라고 생각됩니다. 저도 그랬기 때문이지요.
그래서 bind
에 대해 좀 더 연습을 해보도록 하겠습니다.
일단 bind
란 어떤 함수를 실행할 때 그 함수 안에서의 this
를 지정시켜주는 역할을 합니다.
this
라는 것은 언제나 고정이 아닙니다. 그때 그때 바뀔 수 있고 있다.
이걸 인지하는 것이 가장 중요합니다.
한번 예를 볼까요?
/**
* Sample React Native App
* https://github.com/facebook/react-native
* @flow
*/
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
TextInput,
TouchableOpacity
} from 'react-native';
console.log('check')
class TodoItem extends Component {
completeTodo(index) {
let todos = this.state.todos
todos[index].complete = !todos[index].complete
this.setState({
todos: todos,
})
}
deleteTodo (index) {
let todos = this.state.todos
todos.splice(index, 1)
this.setState({
todos: todos,
})
}
render() {
let todoItem = this.props.item
console.log(this.props)
let index = this.props.index
return(
<View style={{flexDirection: 'row'}}>
<Text style={todoItem.complete ? {textDecorationLine: 'line-through'} : {textDecorationLine: 'none'}}>
{todoItem.context}
</Text>
<TouchableOpacity onPress={this.completeTodo.bind(this.props.todoApp, index)}>
<Text>{todoItem.complete ? "---complete" : "---incomplete" }</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.deleteTodo.bind(this.props.todoApp, index)}>
<Text> delete </Text>
</TouchableOpacity>
</View>
)
}
}
class gitbookTest2 extends Component {
componentWillMount() {
this.setState({
inputText: '',
todos: [],
})
}
addTodo() {
let todoItem = {
context: this.state.inputText,
complete: false
}
let todos = this.state.todos
todos.push(todoItem)
this.setState({
inputText: '',
todos: todos,
})
}
render() {
return (
<View style={styles.container}>
<TextInput
style={{height: 40,borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => {
this.setState({inputText: text})
}}
value={this.state.inputText}
/>
<TouchableOpacity onPress={this.addTodo.bind(this)}>
<Text>
add Todo
</Text>
</TouchableOpacity>
{
this.state.todos.map((todoItem, index)=> {
console.log(todoItem)
console.log(index)
return (
<TodoItem item={todoItem} key={index} index={index} todoApp={this}/>
)
})
}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
});
AppRegistry.registerComponent('gitbookTest2', () => gitbookTest2);
이걸 한번 실행시켜보죠? 아마 그 전과 똑같이 실행이 될 것 입니다. 여기서 주목 해야하는 건
completeTodo(index) {
let todos = this.state.todos
todos[index].complete = !todos[index].complete
this.setState({
todos: todos,
})
}
deleteTodo (index) {
let todos = this.state.todos
todos.splice(index, 1)
this.setState({
todos: todos,
})
}
이 부분 입니다. 이 두 함수가 TodoItem
이라는 컴포넌트안에 들어 있습니다.
근데 todos의 state을 가지고 있는건 gitbookTest2
라는 컴포넌트 입니다.
일반적으로 생각을 하면 TodoItem은 todos라는 state을 가지고 있지 않기 때문에 error가 생길 것 같지만 아닙니다. 그 이유는
<TouchableOpacity onPress={this.completeTodo.bind(this.props.todoApp, index)}>
<Text>{todoItem.complete ? "---complete" : "---incomplete" }</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.deleteTodo.bind(this.props.todoApp, index)}>
<Text> delete </Text>
</TouchableOpacity>
이 안의 onPress
을 봐볼까요?
onPress={this.completeTodo.bind(this.props.todoApp, index)}
여기서는 bind뒤에 this.props.todoApp 이라는 것을 사용하였네요. 그 뒤는 함수에 필요한 인자이구요. 그렇다면 이 this.props.todoApp이 무엇일까요?
<TodoItem item={todoItem} key={index} index={index} todoApp={this}/>
바로 여기서 todoApp={this}
을 하였습니다. 즉 todoApp에 gitbookTest2 자기자신을 넣은것 이지요.
디버그창에서 확인하면 실제로 gitbookTest2가 들어가 있는 것을 확인 할 수 있습니다.
즉 bind(this.props.todoApp)을 통해서 우리는 completeTodo가 실행될때는 this가 gitbookTest2 를 의미한다는 것을 알 수 있습니다. this가 gitbookTest2이기 때문에 실제로 this.setState는 todoIte.setState가 아니라 gitbookTest2.setState을 의미하게 됩니다. 이렇게 우리는 todoItem 안에서 gitbookTest2의 state 값을 변경 할 수 있었습니다.
이제 어느정도 bind에 대한 이해가 잡혔을 것이라고 생각이 됩니다.