본문 바로가기

⭐ React + SpringBoot

기본 흐름 분석

1. React의 특징

- 단방향 데이터 흐름 (one-way data flow)

- 데이트 흐름 : 하향식리액트의 큰 특징은 위에서 아래로 내려가는 단방향 데이터 흐름 이다.

- props (변하지 않는값 이다.)

→ 컴포넌트 외부에서 props를 이용해 데이터를 전달 받을 수 있다.

그리고 데이터를 전달해주는 주체가 부모 컴포넌트가 된다. 받는 컴포넌트는 props를 통해 전달 받은 데이터의 출처를 알지 못하고 부모 컴포넌트로부터 받기만 한다.

- state (변하는 값 이다.)

→ 사용자가 요청한 이벤트에 따라 변경이 가능하다. 이것을 상태로써 관리한다.

어떤 사용자가 게시물을 추가 및 삭제 할때 이벤트가 변경 되므로 이는 props가 아닌 state로 두고 관리를 해야한다.

- state (상태) 끌어올리기

리액트의 특증은 위에서 언급 했듯이 단방향 데이터 흐름이다.

하지만 만약 자식 컴포넌트에 의해 부모 컴포넌트가 바뀌는 상황이 발생 한다면?

예를 들어 어떤 이벤트가 발생 했을때 부모의 상태도 변화되는 경우가 있다. 단방향 데이터 흐림인 리액트가 하위 컴포넌트에서의 어떠한 이벤트로 인해 상위 컴포넌트의 상태가 변경 되는 경우, 해당 문제를 해결하기 위해 state 끌어올리기(Lifting state up)이 있다. 상태를 변경시키는 함수 자체를 하위 컴포넌트에 props로 전달하여 문제를 해결할 수 있다. (나중에 코드로 확인해 보자.)

2. 기본적인 데이터 흐름

2022.05.17 - [⭐ React (리액트)/리액트 기본] - 2. 리액트 실행흐름 이해하기

 

2. 리액트 실행흐름 이해하기

패키지.json 파일에서 아래와 같은 스크립트가 실행을 시키는 구조이다. "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts..

may9noy.tistory.com

실행 흐름 : npm start → index.js → App.js → index.html 실행 된다.

index.js에서 <App /> 즉 App.js를 실행시키고, document.getElementById('root') 는 index.html 의 <div id="root"></div> 를 찾아간다.  그리고 <body> </body> 부분에 App.js 내용이 삽입 된다고 보면 된다.

3. React부터 SpringBoot 까지의 흐름을 분석

react+springboot 데이터 흐름 정리.drawio
0.13MB

① npm start를 하면 index.js 파일이 실행 된다.

index.js 파일을 보면 app.js를 index.html의 root 경로에 실행을 하도록 구현 되어 있다. 아래 코드를 참고

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

② app.js 파일이다.

app.js 파일을 보면 아래와 같이 component 별로 api 주소가 맵핑되어 있는것을 확인 할 수 있다.

- 참고로 나중에 eks ingress의 front주소를 맵핑할때 해당 api 주소를 참고하여 맵핑을 진행해야 한다.

            <Switch>
              <Route path = "/" exact component = {ListBoardComponent}></Route>
              <Route path = "/board" component = {ListBoardComponent}></Route>
              <Route path = "/create-board/:no" component = {CreateBoardComponent}></Route>
              <Route path = "/read-board/:no" component = {ReadBoardComponent}></Route>
              <Route path = "/member-join" component = {JoinMemberComponent}></Route>
            </Switch>

③ index.html 파일이다.

아래의 코드에서 id="root"는 index.js의 document.getElementById('root') 값과 매핑되어 실행된다.

아래의 코드에서 <body> </body> 사이에 app.js 의 내용이 맵핑되어 실행된다.  

    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      여기에 app.js 파일의 내용이 실행된다.
    -->
  </body>

④ ListBoardComponent.jsx 파일을 예시로 보면 아래와 같다.

- 클래스 영역과 메소드 영역으로 나눌수 있다.

- 클래스 영역

class ListBoardComponent extends Component {
    constructor(props) {
        super(props)

        this.state = {
            p_num: 1,
            paging: {},
            boards: []
        }

        this.createBoard = this.createBoard.bind(this);
        console.log("로그출력: ", this.createBoard);
    }

- 메소드 영역

    listBoard(p_num) {
        console.log("pageNum : "+ p_num);
        BoardService.getBoards(p_num).then((res) => {
            console.log(res.data);

            this.setState({ 
                p_num: res.data.pagingData.currentPageNum,
                paging: res.data.pagingData,
                boards: res.data.list});
                console.log("로그 출력 입니다.: ", this.state.boards);
        });
    }

- html 영역: 메소드 값을 사용하여 구현하는 영역

            <div>
                <h2 className="text-center">Boards List</h2>
                <div className = "row">
                    <button className="btn btn-primary" onClick={this.createBoard}> 글 작성</button>
                </div>
                <div className ="row">
                    <table className="table table-striped table-bordered">
                        <thead>
                            <tr>
                                <th>글 번호</th>
                                <th>타이틀 </th>
                                <th>작성자 </th>
                                <th>작성일 </th>
                                <th>갱신일 </th>
                                <th>좋아요수</th>
                                <th>조회수</th>
                            </tr>
                        </thead>
                        <tbody>
                            {
                                this.state.boards.map(
                                    board => 
                                    <tr key = {board.no}>
                                        <td> {board.no} </td>
                                        <td> <a onClick = {() => this.readBoard(board.no)}>{board.title} </a></td>
                                        <td> {board.memberNo} </td>
                                        <td> {board.createdTime} </td>
                                        <td> {board.updatedTime} </td>
                                        <td> {board.likes} </td>
                                        <td> {board.counts} </td>
                                    </tr>
                                )
                            }
                        </tbody>
                    </table>
                </div>

⑤ React service 영역과 SpringBoot의 백엔드 API 영역이 서로 연동되어 실행된다.

⑥ React service 영역 (BoardService)

const BOARD_API_BASE_URL = "http://localhost:8080/api/board";

class BoardService {

    getBoards(p_num) {
        return axios.get(BOARD_API_BASE_URL + "?p_num="+ p_num);
    }

    createBoard(board) {
        return axios.post(BOARD_API_BASE_URL, board);
    }

    getOneBoard(no) {
        return axios.get(BOARD_API_BASE_URL + "/" + no);
    }

    updateBoard(no, board) {
        return axios.put(BOARD_API_BASE_URL + "/" + no, board);
    }

    deleteBoard(no) {
        return axios.delete(BOARD_API_BASE_URL + "/" + no);
    }

⑦ SpringBoot API 영역

- BoardController의 전체 코드

@CrossOrigin(origins = "http://localhost:3000")
@RestController
@RequestMapping("/api")
public class BoardController {
	
	@Autowired
	private BoardService boardService;
	
	// get paging board 
	@GetMapping("/board")
	public ResponseEntity<Map> getAllBoards(@RequestParam(value = "p_num", required=false) Integer p_num) {
		if (p_num == null || p_num <= 0) p_num = 1;
		
		return boardService.getPagingBoard(p_num);
	}

	// create board
	@PostMapping("/board")
	public Board createBoard(@RequestBody Board board) {
		System.out.println("@PostMapping(\"/board\")");
		System.out.println(board.toString());
		return boardService.createBoard(board);
	}
	
	// get board
	@GetMapping("/board/{no}")
	public ResponseEntity<Board> getBoardByNo(
			@PathVariable Integer no) {
		
		return boardService.getBoard(no);
	}
	
	// update board
	@PutMapping("/board/{no}")
	public ResponseEntity<Board> updateBoardByNo(
			@PathVariable Integer no, @RequestBody Board board){
		
		return boardService.updateBoard(no, board);
	}
	
	// delete board
	@DeleteMapping("/board/{no}")
	public ResponseEntity<Map<String, Boolean>> deleteBoardByNo(
			@PathVariable Integer no) {
		
		return boardService.deleteBoard(no);
	}
	
}

'⭐ React + SpringBoot' 카테고리의 다른 글

React와 SpringBoot의 흐름, 간단정리  (0) 2022.10.27