버튼을 클릭할때 마다 버튼 색깔이 변하도록 만들어 보자.
useState를 사용하여 isSelect라는 변수를 false 로 초기화 한 후 button을 클릭할 때마다 isSelect 의 상태를 변경시켜주면된다.
이 단순해 보이는 작업에서 isSelect의 상태를 올바르게 업데이트 하지 않은 경우 아무런 동작이 일어나지 않는 것 처럼 보일 수 있는데, 오늘은 이 잘못 업데이트 하는 경우와 바르게 업데이트 하는 경우(배열형태와 딕셔너리 형태)를 비교하여 볼 예정이다.
원하는 결과를 미리보면 아래와 같다.
1. 문제 코드
useState 를 사용하여 버튼의 갯수만큼 false 배열을 초기화해 준다.
const [isSelect, setSelect] = useState([false, false, false]);
이후 getButton 이라는 함수를 만들어 버튼의 id(초기화한 배열의 인덱스)를 파라미터로 정의해 아래와 같은 함수를 만든다.
→ tempSelect 라는 변수에 isSelect 를 불러와 argument로 받은 id의 값에 따라 해당 인덱스에 원래의 반대 값을 넣어주는 코드이다.(tempSelect[id] 자리를 boolean 값을 변경해 isSelect 에 넣어준다.)
const getButton = (id: number) => {
return (
<Pressable
style={[
styles.buttonContainer,
{backgroundColor: isSelect[id] ? 'green' : 'yellow'},
]}
onPress={() => {
let tempSelect = isSelect;
tempSelect[id] = !tempSelect[id];
setSelect(tempSelect);
}}>
<Text>Color Change Button</Text>
</Pressable>
);
};
그러나 이는 동작하지 않는다.
이는 state를 올바르게 업데이트 해주지 않았기 때문에 발생하는 문제이다.
javascript 에서는 변수에 객체를 저장했을 때 실제 값을 저장하는 것이 아닌 주소 값을 저장한다. 실제로 react 에서 상태가 변경되었을 때는 '얕은 비교'를 통해 상태를 비교하는데, 즉 실제 값이 아닌 참조 값을 비교한다. 여기서는 isSelect 의 실제 값은 변경되었지만, 실제로 isSelect의 참조값이 업데이트 되지 않았기 버튼의 색이 변경되지 않았다.
해당 문제를 해결하기 위해서 spread 문법을 이용해 아래와 같이 고칠 수 있다.
const getButton = (id: number) => {
return (
<Pressable
style={[
styles.buttonContainer,
{backgroundColor: isSelect[id] ? 'green' : 'yellow'},
]}
onPress={() => {
setSelect([
...isSelect.slice(0, id),
!isSelect[id],
...isSelect.slice(id + 1),
]);
}}>
<Text>Color Change Button</Text>
</Pressable>
);
};
추가로 딕셔너리 형태의 자료형은 변수 형태의 객체 키를 가져올때 어려움이 있었는데, [id]: 상태값 형태로 값을 업데이트 할 수 있었다.
같은 내용을 딕셔너리 형태의 자료형으로 변경한 코드는 아래와 같다.
const [isSelect, setSelect] = useState<any>({
id1: false,
id2: false,
id3: false,
});
const getButton = (id: string) => {
return (
<Pressable
style={[
styles.buttonContainer,
{backgroundColor: isSelect[id] ? 'green' : 'yellow'},
]}
onPress={() => {
setSelect({...isSelect, [id]: !isSelect[id]});
}}>
<Text>Color Change Button</Text>
</Pressable>
);
};
코드 전문은 아래와 같다.
import React, {useState} from 'react';
import {Pressable, SafeAreaView, StyleSheet, Text} from 'react-native';
const Button_Dictionary = () => {
const [isSelect, setSelect] = useState([false, false, false]);
const getButton = (id: number) => {
return (
<Pressable
style={[
styles.buttonContainer,
{backgroundColor: isSelect[id] ? 'green' : 'yellow'},
]}
onPress={() => {
setSelect([
...isSelect.slice(0, id),
!isSelect[id],
...isSelect.slice(id + 1),
]);
}}>
<Text>Color Change Button</Text>
</Pressable>
);
};
return (
<SafeAreaView style={styles.Container}>
{getButton(0)}
{getButton(1)}
{getButton(2)}
</SafeAreaView>
);
};
const styles = StyleSheet.create({
Container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
buttonContainer: {
justifyContent: 'center',
alignItems: 'center',
width: 200,
height: 50,
borderRadius: 30,
marginBottom: 15,
},
});
export default Button_Dictionary;
'프로그래밍 > React, React-Native' 카테고리의 다른 글
Bottom tabs navigator 배치하기 - 2(아이콘, 배경색) (0) | 2022.03.21 |
---|---|
Bottom tabs navigator 배치하기 - 1 (0) | 2022.03.20 |
공용 Text 컴포넌트 만들기 (0) | 2022.03.17 |