이걸 위해 정말 정말 정말 애를 썼는데
하루를 다 쓰고 나서야 완성...
눈물이 나요...
그치만 난 울지 않아
으른이니까!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
처음 생각했던 방식은
월~금 다섯 버튼의 isPressed T/F를 확인할 배열을 만들고
버튼을 누르면 누른 버튼만 true, 나머지는 false로 돌려서
true인 경우에 배경 색을 바꾸는 방식을 하려고 했었다
근데 웬 걸
true 출력은 잘 되는데 막상 색은 안 바뀌더라고ㅠㅠ
그래서 다시 구글구글링...
구선생님의 도움으로 정말 좋은 코드를 하나 찾았다!
TouchableOpacity background change onClick - Snack
Change background color of particular TouchableOpacity you are clicking
snack.expo.dev
많은 자료들이 그렇듯 이 코드도 함수형이 아닌 클래스형이어서
함수형으로 바꾸고, 불필요한 부분은 날리고...
내가 원하는 방식으로 손 봐서 성공!
우선 원본 코드를 먼저 뜯어 보자!
import * as React from 'react';
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
categes: [
{ cat_id: '1', cat_name: 'abc', backgroundcolor: '#ED2525' },
{ cat_id: '2', cat_name: 'xyz', backgroundcolor: '#ED2525' },
{ cat_id: '3', cat_name: 'pqr', backgroundcolor: '#ED2525' },
{ cat_id: '4', cat_name: 'uvw', backgroundcolor: '#ED2525' },
{ cat_id: '5', cat_name: 'hij', backgroundcolor: '#ED2525' },
],
change: false,
};
}
changeBackground = item => {
let categes = JSON.parse(JSON.stringify(this.state.categes));
for (let x = 0; x < this.state.categes.length; x++) {
if (this.state.categes[x].cat_id == item.cat_id) {
categes[x].backgroundcolor = '#0000FF';
this.setState({
categes: categes,
});
} else {
categes[x].backgroundcolor = '#ED2525';
this.setState({
categes: categes,
});
}
}
};
render() {
return (
<View style={styles.container}>
{this.state.categes.map((item, key) => (
<TouchableOpacity
style={{
width: 200,
height: 60,
alignItems: 'center',
justifyContent: 'center',
margin: 10,
backgroundColor: item.backgroundcolor,
}}
onPress={() => this.changeBackground(item)}>
<Text style={{ color: '#FFFFFF' }}>
{' '}
{item.cat_name.toUpperCase()}
</Text>
</TouchableOpacity>
))}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#ecf0f1',
padding: 8,
alignItems: 'center',
},
});
여기서 내가 써먹을 수 있는 부분은
애타게(?) 찾았던 버튼의 컴포넌트화 방법!
return 부분에 월~금 버튼을 똑같이 적어두는게 비효율적인 건 알았지만
어떻게 하면 좋을지 몰랐는데 여기에 딱! 방법이 있어서
고대로 이용했다.
먼저 위에서부터 하나씩 살펴보면
함수형이므로 constructor가 아닌 useState로 바꿔줬다.
이에 useState 접근이 훨씬 편해졌다.
마지막에 있던 change는 사용되지도 않고
없어도 잘 작동하기 때문에 삭제 했다.
export default function lunchMenu() {
const [dayBtns, setDayBtns] = useState({
// 한 컴포넌트에 반복해서 넣을 데이터를 categs 안에 넣어주기
categes: [
{ cat_id: "1", cat_name: "abc", backgroundcolor: "#ED2525" },
{ cat_id: "2", cat_name: "xyz", backgroundcolor: "#ED2525" },
{ cat_id: "3", cat_name: "pqr", backgroundcolor: "#ED2525" },
{ cat_id: "4", cat_name: "uvw", backgroundcolor: "#ED2525" },
{ cat_id: "5", cat_name: "hij", backgroundcolor: "#ED2525" },
],
});
배경 색을 바꾸는 함수는 다음과 같이 바꿔주었다
원래 있던 JSON.stringify는 필요 없어서 지워줬다.
여기서 궁금했던게, 원본 코드는
객체{} 안에 categes라는 키에 다시 배열[]을 담고
그 배열안에서 객체{} 가 반복되는 식인데
굳이 이래야 하나? 싶어서 한번
맨 바깥 객체와 categes를 없앴더니 오류가 났다
다른 부분이 아니라 setDaybtns에 다시 catege:categes하는 파트에서!!
dayBtns에 값을 다시 넣는(setDayBtns 함수 호출) 일을 하지 않으면
색이 전혀 바뀌지 않기 때문에
이 부분을 위해서 원래 코드대로 갔다.
const changeBackground = (item) => {
// 원래 코드 : let categes = JSON.parse(JSON.stringify(this.state.categes));
// parsing이 필요없으므로 그대로 받아서 넣어줬다
let categes = dayBtns.categes;
// 배열을 돌면서 눌러진 아이템(버튼)의 id와 배열 내 요소의 id가 같은지 확인
for (let x = 0; x < categes.length; x++) {
// 같다면 선택된 아이템 => 배경색 바꿔주기
if (categes[x].cat_id == item.cat_id) {
categes[x].backgroundcolor = "#0000FF";
// 바꾼 것 반영
setDayBtns({
categes: categes,
});
} else {
// 다르다면 그냥 그대로 (이전에 선택한 것 리셋)
categes[x].backgroundcolor = "#ED2525";
// 바꾼 것 반영
setDayBtns({
categes: categes,
});
}
}
};
그리고 화면에 보이는 부분은 이렇게!
return (
<View style={styles.container}>
{/* dayBtns의 categes안에 있는 요소들을 map함수를 써서 정리(?) */}
{dayBtns.categes.map((item) => (
{/* 스타일 두 개 적용 */}
<TouchableOpacity
style={[styles.dayButton, { backgroundColor: item.backgroundcolor }]}
{/* onpress일때 색바뀌는 함수 호출 */}
onPress={() => changeBackground(item)}
>
<Text style={{ color: "#FFFFFF" }}>
{" "}
{item.cat_name.toUpperCase()}
</Text>
</TouchableOpacity>
))}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
backgroundColor: "#ecf0f1",
padding: 8,
alignItems: "center",
},
dayButton: {
marginHorizontal: 5,
paddingHorizontal: 20,
paddingVertical: 5,
borderRadius: 5,
height: "auto",
flexDirection: "row",
alignItems: "center",
},
});
그러면 누른 버튼 색만 바뀌고(유지!!!!!!!!)
그리고 다른 버튼은 기본 색으로 바뀐다.
찾아보면 TouchableHighlight라는게 있는데
이거는 press/touch 순간에만 색이 바뀌어서
내가 원하는 게 아니었다ㅜㅜ
무튼 해결 완료...!
코드 보면 일단 복붙해서 어떻게 동작하는 건지 뜯어보고
그다음에 내 방식으로 바꾸는게 맞는 것 같다.
한참 눈으로 보고
바로 내 식대로 바꿨더니 오류ㅠ 흑흑
이제는 안 그러겠습니다 ~!
(참고용)
최종 연습본
import { React, useState } from "react";
import { View, Text, StyleSheet, TouchableOpacity } from "react-native";
export default function lunchMenu() {
const [dayBtns, setDayBtns] = useState({
categes: [
{ cat_id: "1", cat_name: "abc", backgroundcolor: "#ED2525" },
{ cat_id: "2", cat_name: "xyz", backgroundcolor: "#ED2525" },
{ cat_id: "3", cat_name: "pqr", backgroundcolor: "#ED2525" },
{ cat_id: "4", cat_name: "uvw", backgroundcolor: "#ED2525" },
{ cat_id: "5", cat_name: "hij", backgroundcolor: "#ED2525" },
],
});
const changeBackground = (item) => {
let categes = dayBtns.categes;
for (let x = 0; x < categes.length; x++) {
if (categes[x].cat_id == item.cat_id) {
categes[x].backgroundcolor = "#0000FF";
setDayBtns({
categes: categes,
});
} else {
categes[x].backgroundcolor = "#ED2525";
setDayBtns({
categes: categes,
});
}
}
};
return (
<View style={styles.container}>
{dayBtns.categes.map((item) => (
<TouchableOpacity
style={[styles.dayButton, { backgroundColor: item.backgroundcolor }]}
onPress={() => changeBackground(item)}
>
<Text style={{ color: "#FFFFFF" }}>
{" "}
{item.cat_name.toUpperCase()}
</Text>
</TouchableOpacity>
))}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
backgroundColor: "#ecf0f1",
padding: 8,
alignItems: "center",
},
dayButton: {
marginHorizontal: 5,
paddingHorizontal: 20,
paddingVertical: 5,
borderRadius: 5,
height: "auto",
flexDirection: "row",
alignItems: "center",
},
});
'TIL > React Native' 카테고리의 다른 글
| [React Native] 그림자 효과 주기 (Box Shadow, dropshadow) (0) | 2022.08.16 |
|---|---|
| [React Native] 패키지 설치 시 spawn yarnpkg ENOENT 에러가 뜰 때 (0) | 2022.08.16 |
| [React Native] 마운트 된 이후에 axios 응답이 도착할 때! (5) | 2022.08.13 |
| [React Native] expo-font와 Font.loadAsync 오류 (0) | 2022.08.12 |
| [React Native] 서버 켜는 방법 (java spring boot) (0) | 2022.08.09 |