1. 컨트롤러
axios를 통해 JSON 형태로 데이터를 주고 받는다. 이 때 axios가 url 패턴을 찾아서 값을 전달해줘야 하는데 다음과 같은 컨트롤러를 통해 값을 전달하고 결과를 받아온다.
import com.hwangduil.springbootbackend.dto.BbsDto;
import com.hwangduil.springbootbackend.service.BbsService;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequiredArgsConstructor
public class BbsController {
public final Logger logger = LoggerFactory.getLogger(BbsController.class);
private final BbsService service;
@GetMapping("/getBbsList")
public List<BbsDto> getBbsList() {
logger.info("BbsController getBbsList");
return service.getBbsList();
}
@GetMapping("/insertBbs")
public String insertBbs(BbsDto dto) {
logger.info("BbsController insertBbs() ");
boolean isInsert = service.insertBbs(dto);
if (isInsert) {
return "ok";
}
return "no";
}
@GetMapping("/getBbsDetail")
public BbsDto getBbsDetail(int seq) {
logger.info("BbsController getBbsDetail()");
service.readcount(seq);
return service.getBbsDetail(seq);
}
}
2. App.tsx에 네비게이션 메뉴 준비
name
으로 전달받은 값을 통해 특정 화면으로 이동하도록 하기 위해서는 NavigationContainer
와 Stack
이 필요하다.
import React from "react";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import Login from "./src/screens/members/Login";
import Account from "./src/screens/members/Account";
import Bbs from "./src/screens/bbs/Bbs";
/*
필수 설치 패키지 목록
npm install @react-navigation/native
npm install @react-navigation/native-stack
npm install react-native-safe-area-context
npm install react-native-gesture-handler
npm install react-native-screens
npm install watcher
npm i @react-native-async-storage/async-storage
*/
const Stack = createNativeStackNavigator();
export default function App() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="login">
<Stack.Screen name="login" component={Login} options={{title: "로그인"}} />
<Stack.Screen name="account" component={Account} options={{title: "회원가입"}} />
<Stack.Screen name="bbs" component={Bbs} options={{title: "게시판"}} />
</Stack.Navigator>
</NavigationContainer>
)
}
title
은 해당 메뉴로 이동했을 때 화면 맨 위에 표시해 줄 제목같은 것이다.
3. 게시글을 보여줄 페이지
import React, { useState } from "react";
import { Button, StyleSheet, Text, View } from "react-native";
import BbsDetail from "./BbsDetail";
import Bbslist from "./Bbslist";
import BbsWrite from "./BbsWrite";
const Bbs = (props:any) => {
const [bbslist, setBbslist] = useState("bbslist");
const [bbs, setBbs] = useState([]); // json 형태로 받기 때문에 배열 괄호로 선언해둔다.
let child:any // 장면 전환을 위한 변수
if (bbslist === "bbslist") {
// child = (<Text>Bbs List View</Text>)
child = (<Bbslist setBbslist={setBbslist} setBbs={setBbs} />)
} else if (bbslist === "bbswrite") {
// child = (<Text>Bbs List Write</Text>)
child = (<BbsWrite setBbslist={setBbslist} />)
} else if (bbslist === "bbsdetail") {
// child = (<Text>Bbs List Detail {JSON.stringify(bbs)}</Text>)
child = (<BbsDetail bbs={bbs} />)
}
child
는 장면의 전환을 위해 선언한 변수로 각 컴포넌트의 값으로 저정해둔다. 이 때 setter
의 값을 그대로 전달하는데, 해당 컴포넌트에서 전달 값을 받기 위해 props
라는 매개변수가 사용될 것이다.
return (
<View>
<View style={styles.menu}>
<View style={styles.button}>
<Button title="글목록" onPress={(bbslist) => setBbslist("bbslist")} />
</View>
<View style={styles.button}>
<Button title="글추가" onPress={(bbslist) => setBbslist("bbswrite")} />
</View>
</View>
<View>{child}</View>
</View>
)
}
const styles = StyleSheet.create({
menu: {
flexDirection: "row",
flexWrap: "wrap",
},
button: {
flex: 1,
height: 50,
margin: 1
},
childView: {
height: 760
}
})
export default Bbs;
페이지 상단에는 두개의 버튼이 존재하는데, 이 버튼을 클릭하면 setBbslist
를 각 페이지의 이름으로 설정해준다.
4. 게시글 목록 가져오기
DB로 부터 게시글 목록을 가져오기 위해 서버로부터 리스트 형식으로 가져와야한다.
axios를 사용하여 getBbsList
에 값을 보내주어 반환 받는다.
import axios from "axios";
import React, { useEffect, useState } from "react";
import { FlatList, Image, StyleSheet, Text, View, TouchableOpacity } from "react-native";
// import { TouchableOpacity } from "react-native-gesture-handler";
/*
일반적으로 화면단을 설정할 때 컨텐츠가 화면을 벗어나면 스크롤뷰를 설정해야 화면을 내려서 볼 수 있지만,
플랫 리스트를 사용하면 스크롤뷰가 내장되어 있기 때문에 별도로 설정하지 않아도 된다.
*/
// test data
// const data = [
// {
// "userId": "admin",
// "title": "테스트 데이터 제목입니다.",
// "readCount": 10
// },
// {
// "userId": "guest",
// "title": "게스트입니다.",
// "readCount": 1
// },
// {
// "userId": "hJunPark",
// "title": "박군입니다.",
// "readCount": 100
// }
// ]
function Item ({id, title, readCount, seq, props}:any) {
function itemClick(seq:number) {
console.log('itemClick');
console.log(seq);
axios.get("http://192.168.35.149:3000/getBbsDetail", {params: {seq: seq}}).then(function(resp) {
console.log(resp.data);
// 페이지 이동 시 가져갈 정보
props.setBbs(resp.data);
}).catch(function(err) {
console.log(err);
})
// detail 페이지로 이동
props.setBbslist("bbsdetail")
}
이 때 props
를 통해 다른 컴포넌트에서 값을 전달하게 해준다. 하단의 Bbslist
컴포넌트에 전달해준다.
return (
<View style={styles.item}>
<TouchableOpacity onPress={() => itemClick(seq)}>
<View style={styles.idRow}>
<Image style={styles.image}
source={require("../../assets/dog.png")}
/>
<Text style={styles.title}>{title}</Text>
</View>
<View style={styles.idRow}>
<Text style={styles.userId}>{id}</Text>
<Text style={styles.readCount}>{readCount}</Text>
</View>
</TouchableOpacity>
</View>
)
}
TouchableOpacity
는 HTML의 <a>
태그 같은 것이다.
const Bbslist = (props:any) => {
function renderItem({item}:any) {
// 제목이 긴 경우 줄여서 표현해 줄 함수
function strLength(str:String) {
if(str.length > 18) {
return str.substring(0, 17) + "...";
} else {
return str;
}
}
return (
<Item
id={`작성자: ${item.userId}`}
title={strLength(item.title)}
readCount={`조회수: ${item.readCount}`}
seq={item.seq}
props={props}
/>
)
}
플랫 리스트를 사용하기 위해 renderItem
함수를 만들어주었다.
const [data, setData] = useState([]);
useEffect(() => {
axios.get("http://192.168.35.149:3000/getBbsList", {})
.then(function(resp) {
console.log(resp);
setData(resp.data);
})
.catch(function(err) {
console.log(err);
});
}, [])
return (
<View style={styles.scrollView}>
<FlatList data={data} renderItem={renderItem} />
</View>
)
}
const styles = StyleSheet.create({
item: {
backgroundColor: "#d7d9f4",
padding: 10,
marginVertical: 2,
marginHorizontal: 8,
borderColor: "#ff0000",
borderRadius: 15,
borderStyle: "solid",
borderWidth: 2,
},
image: {
width: 50,
height: 50,
marginTop: 15
},
title: {
fontFamily: "roboto-regular",
paddingLeft: 20,
color: "#400040",
height: 60,
width: 500,
fontSize: 26,
},
userId: {
fontFamily: "roboto-regular",
//backgroundColor: "#ffff00",
color: "#121212",
height: 30,
width: 166,
fontSize: 20,
marginLeft: 80,
marginTop: 8
},
readCount: {
fontFamily: "roboto-regular",
//backgroundColor: "#00ff00",
color: "#121212",
height: 30,
width: 211,
fontSize: 20,
marginLeft: 51,
marginTop: 8,
textAlign: "center",
},
idRow: {
height: 40,
flexDirection: "row",
marginLeft: 5,
},
scrollView: {
height: 760
}
});
export default Bbslist;
5. 글을 추가하기 위한 컴포넌트
import AsyncStorage from "@react-native-async-storage/async-storage";
import axios from "axios";
import React, { useState } from "react";
import { Alert, StyleSheet, Text, View } from "react-native";
import { Button, TextInput } from "react-native-paper";
export default function BbsWrite(props:any) {
const [id, setId] = useState("");
const [title, setTitle] = useState("");
const [content, setContent] = useState("");
const loginData = async () => {
try {
let user = await AsyncStorage.getItem("login");
if (user !== null) {
setId((JSON.parse(user)).id);
}
} catch (err) {
console.log(err);
}
}
loginData();
AsyncStorage
의 setIte\
을 통해 로그인 화면에서 로그인한 사용자의 정보를 저장해주었고, 여기에서 그 값을 조회하여 사용하기 위해 getItem
으로 불러왔다. 이 객체가 null
이 아닐 때 id
는 setter
를 사용해서 불러온 값을 JSON
으로 파싱하고 아이디 값으로 바꿔준다.
값이 제대로 넘어오지 않을 수 있기 때문에 try catch
를 사용했다.
const bbsWriteBtn = () => {
console.log(id);
console.log(title);
console.log(content);
if (title.trim() === "") {
Alert.alert("제목 입력 확인", "제목이 입력되지 않았습니다!");
} else if (content.trim() === "") {
Alert.alert("내용 입력 확인", "내용이 입력되지 않았습니다!")
} else {
axios.get("http://192.168.35.149:3000/insertBbs",
{ params: {
id: id,
title: title,
content: content
}}
).then(function(resp){
console.log(resp.data);
if (resp.data === "ok") {
Alert.alert("등록 완료", "글이 등록되었습니다!");
// Bbs.tsx에서 bbslist가 bbswrite일 때 setBbslist를 이 컴포넌트 함수의 매개변수인 prop로 접근해서 글 등록이 성공하면 bbslist로 돌아감.
props.setBbslist("bbslist");
} else {
Alert.alert("글이 등록되지 않았습니다.", "글이 정상적으로 등록되지 않았습니다. 확인해주세요.");
}
글의 제목, 내용, 작성자 정보를 서버로 전달해서 ok 문자열을 받으면 글이 등록된 것이므로 등록되었다는 알림을 띄워준다. 그리고 Bbslist.tsx에서 bbslist
즉 보여줄 메뉴의 값이 bbswrite
일 때 setBbslist
를 이 컴포넌트 함수의 매개변수인 prop
로 접근해서 글 등록을 성공적으로 수행하였다면 bbslist
로 돌아간다.
}).catch(function(err) {
console.log(err);
Alert.alert("에러 발생", "글을 등록하는 도중에 에러가 발생했습니다!");
})
}
}
return (
<View>
<Text style={styles.text}>새 글 등록하기</Text>
<View style={{alignItems: "center"}}>
<TextInput
style={styles.textInput}
mode="outlined"
label="작성자"
value={id}
editable={false}
/>
<TextInput
style={styles.textInput}
mode="outlined"
label="제목"
value={title}
onChangeText={(title) => setTitle(title)}
/>
<TextInput
style={styles.textArea}
placeholder="내용"
multiline={true}
numberOfLines={20}
value={content}
onChangeText={(content) => setContent(content)}
/>
<Button
mode="outlined"
style={styles.btn}
onPress={bbsWriteBtn}
>
작성 완료
</Button>
</View>
</View>
)
}
const styles = StyleSheet.create({
text: {
marginTop: 10,
fontSize: 30,
textAlign: "center"
},
textInput: {
marginTop: 20,
fontSize: 16,
width: 500,
height: 40,
backgroundColor: "#e3e3e3"
},
textArea: {
fontSize: 16,
borderWidth: 1,
marginTop: 20,
backgroundColor: "#e3e3e3",
textAlignVertical: "top",
width: 500
},
btn: {
marginTop: 20,
marginVertical: 8
}
})
6. 상세 글보기 페이지
import React from "react";
import { SafeAreaView, StyleSheet, ScrollView, Text } from "react-native";
import { Avatar, Card, Headline, Paragraph } from "react-native-paper";
function BbsDetail(props:any) {
let userName = props.bbs.userId.substring(0, 2);
return (
<SafeAreaView>
<ScrollView
contentContainerStyle={styles.contentContainer}
>
<Headline>글 내용</Headline>
<Card style={styles.card}>
<Card.Title
title={props.bbs.title}
subtitle={`작성자: ${props.bbs.userId}`}
left={props =>
<Avatar.Text{...props}
label={userName}
/>
}
/>
<Card.Content>
<Paragraph style={styles.content}>
{props.bbs.content}
</Paragraph>
<Text style={{textAlign: "right"}}>
조회수: {props.bbs.readCount}
</Text>
<Text style={{textAlign: "right"}}>
작성일: {props.bbs.wdate}
</Text>
</Card.Content>
</Card>
</ScrollView>
</SafeAreaView>
);
}
Card
를 통해서 글을 나열해준다.
Bbs
컴포넌트에서 <BbsDetail />
을 불러와 사용할 때, 속성으로 전달해줄 값이 필요한데, useState
로 선언된 bbs
를 전달해준다.
bbs
는 JSON
형태이기 때문에 직접 key
값으로 접근하여 가져올 수 있다.
const styles = StyleSheet.create({
contentContainer: {
padding: 16,
},
card: {
marginTop: 20,
},
content: {
fontSize: 20
}
})
export default BbsDetail;
'Study > React' 카테고리의 다른 글
[React Native] useEffect의 dependency array 사용 시 주의점 (0) | 2022.04.02 |
---|---|
[React Native] 다른 페이지로 값 전달하기 (0) | 2022.03.23 |
[React Native] axios를 사용하여 spring boot로 비동기 통신 하기 (0) | 2022.03.10 |
[React Native] 다른 화면으로 전환하기 (0) | 2022.03.09 |
[React Native] ButtonNavBar 사용하기 (0) | 2022.03.09 |