정리에 앞서, Spring Boot에서 file upload 및 download를 위해 작성된 코드는 다음과 같다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package mul.cam.a.controller;
 
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
 
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest;
import mul.cam.a.MediaTypeUtiles;
import mul.cam.a.dto.HumanDto;
 
@RestController
public class HelloController {
 
    // file upload
    @RequestMapping(value = "/fileUpload", method = RequestMethod.POST)
    public String fileUpload(HumanDto human,
                             @RequestParam("uploadFile")
                             MultipartFile uploadFile,
                             HttpServletRequest req) {
        
        System.out.println("HelloController fileUpload " + new Date());
        System.out.println(human.toString());
        
        // 경로
        String path = req.getServletContext().getRealPath("/upload"); // 서버에 업로드
//        String path = "c:\temp"; // 폴더에 upload
        
        
        String filename = uploadFile.getOriginalFilename(); // 기본 파일명
        String filepath = path + "/" + filename;
        
        System.out.println(filepath);
        
        File file = new File(filepath);
        try {
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
            bos.write(uploadFile.getBytes());
            bos.close();
        
        } catch (Exception e) {
            return "file upload fail";
        } 
        return "file upload success";
        
    }
    
    // file download
    @Autowired
    ServletContext servletContext;
    
    @RequestMapping(value = "/fileDownload")
    public ResponseEntity<InputStreamResource> download(String filename, HttpServletRequest req) throws Exception{
        System.out.println("HelloController download " + new Date());
        
        // 경로
        String path = req.getServletContext().getRealPath("/upload");
        
        MediaType mediaType = MediaTypeUtiles.getMediaTypeForFileName(this.servletContext, filename);
        System.out.println("filename: " + filename);
        System.out.println("mediaType: " + mediaType);
        
        File file = new File(path + "/" + filename); // filename은 업로드됐을 때의 new filename
//        File file = new File(path + File.separator + filename);
        
        InputStreamResource isr = new InputStreamResource(new FileInputStream(file));
        
        // db에서 다운로드 카운트 넣으려면 이 곳에 넣음
        
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + file.getName()) // file.getName()은 원본 파일명
                .contentType(mediaType)
                .contentLength(file.length())
                .body(isr);
    }
    
    
    
    
}
 
cs

 

위 코드에 사용된 static 함수인 getMediaTypeForFileName을 정의한 클래스는

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package mul.cam.a;
 
import org.springframework.http.MediaType;
 
import jakarta.servlet.ServletContext;
 
public class MediaTypeUtiles {
 
    public static MediaType getMediaTypeForFileName(ServletContext servletContext, String filename) {
        
        String minType = servletContext.getMimeType(filename);
        
        try {
            MediaType mediaType = MediaType.parseMediaType(minType);
            return mediaType;
        } catch (Exception e) {
            return MediaType.APPLICATION_OCTET_STREAM;
        }
        
        
    }
}
 
cs

 

 

이제, React 부분을 살펴보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Spring Boot의 sample2-file에 맞춰 작성
 
// npm install axios
import React, {useState} from 'react';
import axios from 'axios';
 
function App() {
 
  // HumanDto 부분
  const [number, setNumber] = useState(''); 
  const [name, setName] = useState('');  
  const [address, setAddress] = useState('');   
 
  const numberChange = (e) => setNumber(e.target.value);
  const nameChange = (e) => setName(e.target.value);
  const addressChange = (e) => setAddress(e.target.value);
 
  const onSubmit = (e) => {
    e.preventDefault(); // 기본 기능과 다르게 만드니까
    
    // alert('onSubmit');
 
    // file + form field -> 짐을 싼다
 
    // /fileUpload 부분에 HumanDto 객체를 참조하는 매개변수를 받는 부분이 있어서 작성하는 것
    let formData = new FormData();
    formData.append("number", number);
    formData.append("name"name);
    formData.append("address", address);
 
    // Spring Boot에서 @RequestParam("uploadFile")에 맞춰라
    formData.append("uploadFile"document.frm.uploadFile.files[0]);
 
    // 보내자!
    axios.post("http://localhost:3000/fileUpload", formData)
    .then(res=>// success
      console.log(res.data);
      alert('file upload에 성공했습니다');
    })
    .catch(function(error){ // error
      alert('file upload에 실패했습니다');
    });
 
  }
 
  // download
  const download = async () => {
    let filename = "abc.txt";
 
    // /fileDownload의 매개변수명인 filename에 맞춘다.
    const url = "http://localhost:3000/fileDownload?filename=" + filename;
 
    /*
    // a tag를 생성하고 자동실행
    const download = document.createElement('a'); // <a> 생성
    download.setAttribute('href', url);
    download.setAttribute('download', filename);
    download.setAttribute('type', 'applicaiton/json');
    download.click();
    */
 
    // react에서는 window를 붙여줘야 한다.
    window.location.href = url;
 
  }
 
 
  return (
    <div>
      <h3>file upload</h3>
      
      <form name="frm" onSubmit={onSubmit} encType="multipart/form-data">
        <input value={number} onChange={numberChange} placeholder='번호' /><br/>
        <input value={name} onChange={nameChange} placeholder='이름' /><br/>
        <input value={address} onChange={addressChange} placeholder='주소' /><br/><br/>   
 
        <input type='file' name="uploadFile" accept='*' />
 
        <input type="submit" value="file upload" />
 
      </form>
 
      <hr/>
 
      <h3>file download</h3>
      <button onClick={download}>file download</button>
 
    </div>
  );
}
 
export default App;
 
cs

 

그 결과는

 

 

 

abc.txt라는 파일을 업로드하고, 다운로드 받아보도록 하겠다. (input 태그도 간단하게 입력하고)

 

 

 

 

끝.

 

 

'React' 카테고리의 다른 글

[React] axios  (0) 2023.03.29
[React] session과 cookie  (0) 2023.03.29
[React] hook - useEffect  (0) 2023.03.29
[React] hook - useState  (0) 2023.03.29
[React] 리액트 시작 및 기초  (0) 2023.03.29

Spring Boot에서 간단하게 만들었던 controller를 가지고 axios를 이해해보자.

 

먼저, 과거 만들었던 Spring Boot 부분

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package mul.cam.a.controller;
 
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
 
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
 
import mul.cam.a.dto.HumanDto;
 
@RestController 
// MVC model에서의 @Controller(controller부분) + @Responsebody(ajax부분)
public class HelloController {
 
    /////////////// 서버(back-end)에서 값을 보내주기만 하는 부분 ////////////////////////
    // http://localhost:3000/
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String hello() {
        System.out.println("HelloController hello() " + new Date());
        
        return "hello"// ajax를 통해 값을 front-end로 보내준다.
    }
    
    // http://localhost:3000/test
    @GetMapping(value = "/test")
    public String test() {
        System.out.println("HelloController test() " + new Date());
        
        return "테스트";
    }
    
    // http://localhost:3000/human
    @GetMapping(value = "/human")
    public HumanDto getDto() {
        System.out.println("HelloController getDto() " + new Date());
        
        HumanDto human = new HumanDto(1001"홍길동""서울시");
        
        return human;
    }
    
    // http://localhost:3000/get_list
    @GetMapping("/get_list")
    public List<HumanDto> get_list(){
        System.out.println("HelloController get_list() " + new Date());
 
        List<HumanDto> list = new ArrayList<>();
        list.add(new HumanDto(101"홍길동""서울시"));
        list.add(new HumanDto(102"성춘향""남원시"));
        list.add(new HumanDto(103"임꺽정""광주시"));
        
        return list;
    }
    
////////////////// 외부에서 데이터를 서버로 보낸 경우, 서버에서 매개변수로 받는 것 /////////////////////
    // 예를 들어, http://localhost:3000/conn_param?title=제목입니다
    @GetMapping(value = "/conn_param")
    public String conn_param(String title) {
        System.out.println("HelloController conn_param() " + new Date());
 
        System.out.println("title: " + title);
        
        return "conn success";
    }
    
    // http://localhost:3000/param_obj?number=1002&name=성춘향&address=남원시
    @GetMapping(value = "param_obj")
    public String param_obj(HumanDto human) {
        System.out.println("HelloController param_obj() " + new Date());
 
        System.out.println("human: " + human);
        
        return "OK";
    }
    
    
    
    
}
 
cs

 

 

axios는 ajax를 대신!!

 

react에서 axios를 사용하기 위해서는 npm install axios를 실행해줘야 한다.

또한, import axios from 'axios'와 같이 import 해줘야 한다.

 

현재 spring boot에서 port number 3000을 사용하고 있으므로, 겹치지 않도록 react의 port number를 미리 변경해주도록 한다.

바꾸는 방법은 package.json 파일에서 

 

 

와 같이 set PORT=포트넘버 && 을 기존 코드 앞에 추가해주면 된다. 

 

Spring Boot의 각 Mapping의 value를 기준으로 나눠서 살펴보자.

 

1. /test

 

Spring Boot 부분

 

1
2
3
4
5
6
7
// http://localhost:3000/test
    @GetMapping(value = "/test")
    public String test() {
        System.out.println("HelloController test() " + new Date());
        
        return "테스트";
    }
cs

 

React 부분

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React, {useEffect, useState} from "react";
import axios from 'axios';
 
function App(){
 
  const fetchData = async () => {
    const response = await axios.get('http://localhost:3000/test', {} )
    console.log(response.data);
  }
 
  useEffect(()=>{
 
    fetchData();
 
  }, []);
 
  return(
    <div>
      <p>axios</p>
    </div>
  )
}
 
export default App;
cs

 

 

결과

 

 

 

 

2. /human

 

Spring Boot 부분

 

1
2
3
4
5
6
7
8
9
// http://localhost:3000/human
    @GetMapping(value = "/human")
    public HumanDto getDto() {
        System.out.println("HelloController getDto() " + new Date());
        
        HumanDto human = new HumanDto(1001"홍길동""서울시");
        
        return human;
    }
cs

 

React 부분

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React, {useEffect, useState} from "react";
import axios from 'axios';
 
function App(){
 
  const fetchData = async () => {
    const response = await axios.get('http://localhost:3000/human', {} )
    console.log(response.data);
  }
 
  useEffect(()=>{
 
    fetchData();
 
  }, []);
 
  return(
    <div>
      <p>axios</p>
    </div>
  )
}
 
export default App;
cs

 

 

결과

 

 

 

3. /conn_param

 

1,2번과 다르게 front-end(react)에서 back-end(spring boot)로 값을 넘겨주고, 다시 넘겨받는 구조이다.

즉, 

const response = await axios.get('http://localhost:3000/test', {} ) // 1번

const response = await axios.get('http://localhost:3000/human', {} ) // 2번

에서는 { } 처럼 넘겨주는 값이 없어서 비어있지만,

 

3번에서는 

const response = await axios.get('http://localhost:3000/conn_param', { params: {title:"제목"} } ) 와 같이

{ params: {title:"제목"} }으로 값을 넘겨준다.

이때, title은 매개변수명이므로 spring boot에서의 매개변수명과 맞춰줘야 한다.

 

Spring Boot 부분

 

1
2
3
4
5
6
7
8
9
// 예를 들어, http://localhost:3000/conn_param?title=제목입니다
    @GetMapping(value = "/conn_param")
    public String conn_param(String title) {
        System.out.println("HelloController conn_param() " + new Date());
 
        System.out.println("title: " + title);
        
        return "conn success";
    }
cs

 

React 부분

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React, {useEffect, useState} from "react";
import axios from 'axios';
 
function App(){
 
  const fetchData = async () => {
    const response = await axios.get('http://localhost:3000/conn_param', { params: {title:"제목"} } )
    console.log(response.data);
  }
 
  useEffect(()=>{
 
    fetchData();
 
  }, []);
 
  return(
    <div>
      <p>axios</p>
    </div>
  )
}
 
export default App;
cs

 

결과

 

 

 

 

 

이제 post 방식으로도 axios를 사용해보자.

 

먼저,  Spring Boot 부분은 아래와 같다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package mul.cam.a.controller;
 
import java.util.Date;
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
 
import mul.cam.a.dto.MemberDto;
import mul.cam.a.service.MemberService;
 
@RestController
public class MemberController {
    
    @Autowired
    MemberService service;
    
    @PostMapping(value = "/allList")
    public List<MemberDto> allList(String user){
        System.out.println("MemberController allList " + new Date());
        
        System.out.println("user: " + user);
        
        return service.allMember();
    }
}
 
cs

 

React 부분

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import React, {useEffect, useState} from "react";
import axios from 'axios';
 
function App(){
 
  const [memberlist, setMemberlist] = useState([]);
 
  // post는 매개변수가 다르다
  // get방식은 2번째 위치에 params가 들어오고,
  // post 방식은 2번째 위치에는 null, 3번째 위치에 params가 들어온다.
  const fetchData = async () => {
  const response = await axios.post('http://localhost:3000/allList'null, { params: {user:"홍길동"} });
  console.log(response.data);
 
  setMemberlist(response.data);
  }
  useEffect(()=>{
 
    fetchData();
 
  }, []);
 
  return(
    <div>
      <h3>axios test</h3>
 
        <table border="1">
          <thead>
            <tr>
              <th>No</th><th>id</th><th>password</th><th>name</th><th>email</th>
            </tr>
          </thead>
          <tbody>
            {
              memberlist.map(function(member, i){
                return (
                  <tr key={i}>
                    <th>{i+1}</th>
                    <td>{member.id}</td>
                    <td>{member.pwd}</td>
                    <td>{member.name}</td>
                    <td>{member.email}</td>
                  </tr>
                )
              })
            }
          </tbody>
 
        </table>
    </div>
  )
}
 
export default App;
cs

 

결과를 보기에 앞서, db에 이미 저장했던 값들이 있어서 아래와 같이 결과가 나타나는 것뿐이지 table 안의 값들은 큰 의미가 없다.

 

 

 

 

이때, react 코드를 아래와 같이 작성할 수도 있다.(table 부분)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import React, {useEffect, useState} from "react";
import axios from 'axios';
 
function App(){
 
  const [memberlist, setMemberlist] = useState([]);
 
  // post는 매개변수가 다르다
  // get방식은 2번째 위치에 params가 들어오고,
  // post 방식은 2번째 위치에는 null, 3번째 위치에 params가 들어온다.
  const fetchData = async () => {
  const response = await axios.post('http://localhost:3000/allList'null, { params: {user:"홍길동"} });
  console.log(response.data);
 
  setMemberlist(response.data);
  }
  useEffect(()=>{
 
    fetchData();
 
  }, []);
 
  return(
    <div>
      <h3>axios test</h3>
 
        <table border="1">
          <thead>
            <tr>
              <th>No</th><th>id</th><th>password</th><th>name</th><th>email</th>
            </tr>
          </thead>
          <tbody>
          {
            memberlist.map(function(member, i){
              return (
                // <tr key={i}>
                //   <th>{i+1}</th>
                //   <td>{member.id}</td>
                //   <td>{member.pwd}</td>
                //   <td>{member.name}</td>
                //   <td>{member.email}</td>
                // </tr>
 
                <TableRow cnt={i + 1} mem={member} key={i} />
              )
            })
          }
        </tbody>
 
      </table>
    </div>
  );
}
 
function TableRow(props){
  return(
    <tr>
      <th>{props.cnt}</th>
      <td>{props.mem.id}</td>
      <td>{props.mem.pwd}</td>
      <td>{props.mem.name}</td>
      <td>{props.mem.email}</td>
    </tr>
  );
}
 
export default App;
cs

 

 

끝.

'React' 카테고리의 다른 글

[React] file upload & download  (0) 2023.03.30
[React] session과 cookie  (0) 2023.03.29
[React] hook - useEffect  (0) 2023.03.29
[React] hook - useState  (0) 2023.03.29
[React] 리액트 시작 및 기초  (0) 2023.03.29

Theme. session

 

우선, session을 사용하기 위해서 npm install react-session-api 를 실행해줘야 한다.

 

session을 사용하는 예를 3가지 정도 나타내보도록 한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import React from 'react';
import Session from 'react-session-api';
 
function App(){
 
  // session 저장하는 함수 정의
  function save(){
    let count = 1024;
    Session.set("counter", count); // Session.set("세션명", 값);
 
  }
 
  // session 불러오는 함수 정의
  function load(){
    let c = Session.get("counter");
    alert(c); // 1024
  }
 
  return(
    <div>
      <h3>session test</h3>
 
      <button onClick={() => save()}>session 저장</button>
 
      <button onClick={() => load()}>session 읽기</button>
 
    </div>
  )
 
}
 
export default App;
cs

 

session 저장, session 읽기 버튼을 순차적으로 클릭한 결과는,

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import React from 'react';
import Session from 'react-session-api';
 
function App(){
 
  // session 저장하는 함수 정의
  function save(){
    let member = { "id":"abc""pw":"123"};
    Session.set("member", member); // Session.set("세션명", 값);
 
  }
 
  // session 불러오는 함수 정의
  function load(){
    let member = Session.get("member");
    // alert(member);
    alert(JSON.stringify(member));
  }
 
  return(
    <div>
      <h3>session test</h3>
 
      <button onClick={() => save()}>session 저장</button>
 
      <button onClick={() => load()}>session 읽기</button>
 
    </div>
  )
 
}
 
export default App;
cs

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import React from 'react';
import Session from 'react-session-api';
 
function App(){
 
  // session 저장하는 함수 정의
  function save(){
    let jsonData = [ { "name":"홍길동""age":24}, { "name":"성춘향""age":16} ];
    Session.set("jsonData", jsonData); // Session.set("세션명", 값);
 
  }
 
  // session 불러오는 함수 정의
  function load(){
    let jsonData = Session.get("jsonData");
    // alert(JSON.stringify(jsonData));
    alert(jsonData[1].age); // 16
  }
 
  return(
    <div>
      <h3>session test</h3>
 
      <button onClick={() => save()}>session 저장</button>
 
      <button onClick={() => load()}>session 읽기</button>
 
    </div>
  )
 
}
 
export default App;
cs

 

 

 

 

 

 

 

Theme. cookie

 

cookie를 사용하기 위해서 npm install react-cookie를 실행해줘야 한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import React, {useState} from 'react';
import {useCookies} from 'react-cookie';
 
function App() {
 
  const [id, setId] = useState("");
 
  // 기존의 cookie를 저장
  const [cookies, setCookies] = useCookies(["id"]);
 
  const changeId = (e) => setId(e.target.value);
 
  // cookid 저장하기
  const cookieSave = () => {
    setCookies("id", id, { path:'/' }); // cookie명, 값, 경로
  }
 
  // cookie 불러오기
  const cookieLoad = () => {
    alert(cookies.id);
  }
 
  return (
    <div>
      <h3>cookie test</h3>
 
      <input value={id} onChange={changeId} /><br/>
 
      <button onClick={cookieSave}>cookie 저장</button>
      <button onClick={cookieLoad}>cookie 불러오기</button>
    </div>
  );
}
 
export default App;
cs

 

그 결과는,

 

 

 

과정을 설명하도록 하자.

처음 id의 초기값은 빈칸이다. 그리고 아직 "id"라는 쿠키명으로 저장된 값이 없는 상태.

따라서, cookies의 값도 없다.

하지만, input에 값을 입력하게 되면, 그 값이 changeId라는 함수에 의해 id에 저장된다.  

이후, cookie 저장이라는 버튼을 누르면 cookieSave 함수를 통해 "id"라는 쿠키명으로 변수 id에 저장된 값(입력된 값)이 저장되게 된다. 또한, useCookies에 의해 cookies라는 변수에 쿠키가 저장된다. 

그리고, cookie 불러오기라는 버튼을 누르게 되면, 저장된 cookie가 불러와진다.

 

 

 

끝.

'React' 카테고리의 다른 글

[React] file upload & download  (0) 2023.03.30
[React] axios  (0) 2023.03.29
[React] hook - useEffect  (0) 2023.03.29
[React] hook - useState  (0) 2023.03.29
[React] 리액트 시작 및 기초  (0) 2023.03.29

Theme. useEffect의 case 분류

 

크게 3가지로 나누어 살펴보도록 한다.

1. rendering이 완료될 때마다 실행되는 경우

2. 처음 rendering이 되었을 때만 실행되는 경우(초기화의 기능)

3. 특정 값(변수)이 변경될 때에만 실행되는 경우

 

아래의 각 코드마다 상위에 

import React, { useEffect, useState } from "react";

를 해줘야함을 잊지 말자.

 

Theme. rendering이 완료될 때마다 실행

 주의: 무한 루프에 빠질 수 있음

코드와 함께 살펴보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function App() {
 
  const [count, setCount] = useState(0); // 초기값 0
 
  const CountUp = () => setCount(count + 1); // count++, count+=1 사용 불가능
 
  // useEffect(함수, 배열)
  useEffect(()=>{
    console.log("useEffect!!", count);
  })
 
  return (
    <div>
      <p>count: {count}</p>
      {/* 클릭하면 count가 바뀌어서 화면에 나타난다. 따라서 useEffect 실행됨 */}
      <button onClick={()=>CountUp()}>count 증가</button>
      {/* <button onClick={CountUp}>counter</button> */}
 
      {/* 클릭해도 화면의 변화는 없다 따라서 useEffect 실행 안됨 */}
      <button onClick={()=>{console.log('클릭')}}>클릭</button> 
    </div>
  );
}
 
export default App;
cs

 

처음 실행하면, useEffect가 실행된다.

즉, count의 초기값은 0이므로 console을 확인해보면, 아래와 같이 실행되는 것을 알 수 있다.

 

또한 UI를 보면,

 

 

count가 증가되는 버튼과 단순히 console에 '클릭'이라는 단어가 찍히는 버튼이 존재한다.

두 가지 버튼의 차이점은 버튼을 눌렀을 때, UI의 변화 여부이다.

 

위 코드에서

 

1
2
3
useEffect(()=>{
    console.log("useEffect!!", count);
  })
cs

 

와 같이 작성해줬기 때문에 화면이 새로 rendering이 될 때마다 useEffect가 실행되게 된다.

 

이때, count 증가 버튼을 누르게 되면 count가 1 증가하게 되는데(CountUp 함수를 정의해뒀으므로)

count: 1으로 새로 rendering이 되기 때문에 useEffect가 실행된다.

아래 결과를 확인해보자.

 

 

하지만 만약, 클릭 버튼을 누르게 되면 단순히 console에 '클릭'이라는 단어가 찍힐 뿐 화면의 변화는 없으므로 새로 rendering이 되지 않는다. 따라서 useEffect는 실행되지 않고 아래와 같은 결과가 나타난다.

 

 

Theme. 처음 rendering이 됐을 때만 실행

 초기화의 기능을 할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function App() {
 
    const [count, setCount] = useState(0);
  
    const CountUp = () => setCount(count + 1); // count++, count+=1 사용 불가능
  
    // useEffect(함수, 배열)
    useEffect(()=>{
      console.log("useEffect!!", count);
    }, [])
  
    return (
      <div>
        <p>count: {count}</p>
        <button onClick={()=>CountUp()}>counter</button>
              </div>
    );
  }
  export default App;
cs

 

위 코드에서 주목할 부분은 아래이다.

 

1
2
3
4
// useEffect(함수, 배열)
    useEffect(()=>{
      console.log("useEffect!!", count);
    }, [])
cs

 

arrow 함수 뒤에 [ ] 이 함께 포함되어 있는데, 이 부분 때문에 처음 rendering 될 때만 useEffect가 실행된다. [ ] 안에 다른 변수가 들어온다면...? 다음 케이스에서 알 수 있다! 

 

위 코드의 결과를 살펴보자.

 

처음 실행됐을 때, useEffect가 실행되는 것을 확인할 수 있다.

 

 

이제 버튼을 눌러 CountUp 함수를 실행시킨 후 결과를 살펴보자.

 

 

count는 증가했지만, useEffect는 실행되지 않음을 확인할 수 있다.

 

 

Theme. 특정 값(변수)이 변경될 때에만 실행되는 예

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function App() {
 
  const [count, setCount] = useState(0);
  const [number, setNubmer] = useState(10);
 
  const CountUp = () => setCount(count + 1); // count++, count+=1 사용 불가능
 
  const NumberDown = () => setNubmer(number - 1);
 
 
  // useEffect(함수, 배열)
  
  useEffect(()=>{
    console.log("useEffect!!", count);
    console.log("useEffect!!", number);
  }, [count]); // count가 변할 때마다 실행 됨(number는 변해도 실행 안됨)
  // [count, number] 였으면 count 또는 number가 변할 때 useEffect 실행됨
  
  return (
    <div>
      <p>count: {count}</p>
      <button onClick={()=>CountUp()}>counter</button>
 
      <p>number: {number}</p>
      <button onClick={()=>NumberDown()}>NumberDown</button>
    </div>
  );
}
 
export default App;
cs

 

위 코드에서 주목해야 할 부분은

 

1
2
3
4
5
6
7
// useEffect(함수, 배열)
  
  useEffect(()=>{
    console.log("useEffect!!", count);
    console.log("useEffect!!", number);
  }, [count]); // count가 변할 때마다 실행 됨(number는 변해도 실행 안됨)
  // [count, number] 였으면 count 또는 number가 변할 때 useEffect 실행됨
cs

 

화면에 count와 number의 값이 나타나므로,

[ ] 안에 들어가는 변수(count 혹은 number)가 변할 때마다 useEffect가 실행된다.

즉, [count] 이면 count가 변할 때마다 useEffect가 실행되고, number가 변하는 것은 영향을 주지 않는다.

만약, [count, number] 였다면 count 또는 number가 변하면 useEffect가 실행된다.

 

처음 실행했을 때는

 

 

 

이를 기준으로 count를 증가시켰을 때,

 

 

처음을 기준으로 number를 감소시켰을 때,

 

 

 

한편, useEffect를 사용하는 다른 코드는 다음과 같다.

이 경우에는 count 또는 number가 변할 때마다 useEffect가 실행되도록 하겠다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function App() {
 
  const [count, setCount] = useState(0);
  const [number, setNubmer] = useState(10);
 
  const CountUp = () => setCount(count + 1); // count++, count+=1 사용 불가능
 
  const NumberDown = () => setNubmer(number - 1);
 
  function EffectFunc(){
    console.log("useEffect!!", count);
    console.log("useEffect!!", number);
  }
  
  useEffect(EffectFunc, [count, number]);
 
  return (
    <div>
      <p>count: {count}</p>
      <button onClick={()=>CountUp()}>counter</button>
 
      <p>number: {number}</p>
      <button onClick={()=>NumberDown()}>NumberDown</button>
    </div>
  );
}
 
export default App;
cs

 

끝.

'React' 카테고리의 다른 글

[React] file upload & download  (0) 2023.03.30
[React] axios  (0) 2023.03.29
[React] session과 cookie  (0) 2023.03.29
[React] hook - useState  (0) 2023.03.29
[React] 리액트 시작 및 기초  (0) 2023.03.29

Theme. useState

 

코드와 함께 알아보도록 한다.

useState 사용을 위해서 import 부분에 추가해주는 것을 잊지 말자.

 

아래 코드의 const [ state, setState ] = useState('click'); 에서

state 부분은 getter 부분

setState는 setter 부분

'click'은 초기값

으로 이해하면 된다!

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// import 작성
import React, { useState } from 'react';
 
 
function App() {
  
  // (보호)변수 선언 -> String state = "click"; 과 같은 효과
  //       get      set                 초기값
  const [ state, setState ] = useState('click');
  
  console.log(state); 
  // state = 'abc'; 에러! - 상수에 대입은 불가능
  // setState('abc'); 에러! - 다시 초기화 할 수 없음
 
  return (
    <div>
      <button onClick={() => setState('clicked')}>{state}</button>
    </div>
  );
}
 
export default App;
cs

 

그 결과 버튼을 누르기 전과 후를 비교하면,

 

 

 

 

간단한 예시들을 추가로 살펴보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const INITIAL_COUNT = 0// 상수
 
function App(){
 
  const [message, setMessage] = useState("");
  const [number, setNumber] = useState(INITIAL_COUNT);
  // const [number, setNumber] = useState(0);
 
  const btnclick = () => {  
    alert(message);
  }
 
  function counterBtn(){
    setNumber(number + 1);
  }
 
  const initCount = () => {
    setNumber(INITIAL_COUNT);
  }
 
  return (
    <div>
      <input onChange={(e) => {setMessage(e.target.value)}} />
 
      <button onClick={btnclick}>message보기</button>
      <button onClick={() => btnclick()}>message보기</button>
 
      <p>{number}</p>
      <button onClick={counterBtn}>카운터</button>
      <button onClick={initCount}>초기화</button>
 
    </div>
  )
}
 
export default App;
cs

 

우선, {btnclick}과 { () => btnclick() }이 같은 효과를 나타내는 것을 확인하기 위해 함께 적어두었다.

 

버튼을 클릭하지 않고, 초기 결과를 살펴보면 아래와 같다.

 

 

onChange 이벤트를 통해 input에 값을 입력하게 되면, 이를 message보기라는 버튼을 통해 확인할 수 있다.(alert)

 

또한, 카운터라는 버튼을 누르면 counterBtn()이 실행되고, setNumber(number + 1);에 의해 초기값 0에서 number가 1 증가하게 된다. (이때 주의할 것은 number++, number+=1과 같이 작성할 수 없다는 것이다) 

 

< input 태그에서의 useState 사용 >

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function App(){
 
  const [inputTextVal, setInputTextVal] = useState("초기값");
  const [text, setText] = useState("React");
 
  const handleChange = (e) => setInputTextVal(e.target.value);
  
  // const handleChange = (e) => {
  //   setInputTextVal(e.target.value);
  // }
 
  const handleClick = () => {
    setText(inputTextVal);
    setInputTextVal("초기값");
  }
 
  return (
    <div>
      <h1>I love {text}</h1>
 
      <input type="text" value={inputTextVal} onChange={handleChange} />
 
      <input type="button" value="입력" onClick={() => handleClick()} />
    </div>
    
  )
 
}
 
export default App;
cs

 

초기 결과는,

 

 

이때, input 태그에 값을 입력하게 되면, onChange 이벤트에 의해 handleChange 함수가 실행된다.

그리고 입력한 값이 handleChange 함수에서 setInputTextVal에 의해 inputTextVal을 변하게 한다.

즉, input의 value값이 입력한 값으로 나타나는 것이다.

이때, '입력'버튼을 누르게 되면(onClick) handleClick 함수가 실행되고, setText를 통해 text의 값을 변하게 한다.

 

그래서 만약 input 태그에 'you'라고 입력하고 입력 버튼을 누르게 되면,

 

 

 

< select 태그에서의 useState 사용 >

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// select
const SelectBox = () => { // Component명의 첫 글자는 대문자 
  const [selectedVal, setSelectedVal] = useState("HTML");
 
  const handleChange = (e) => {
    setSelectedVal(e.target.value);
  }
 
  const SelectChoice = () => {
    alert(selectedVal);
  }
 
 
  return(
    <div>
      <p>현재 선택된 항목: <strong>{selectedVal}</strong></p>
 
      <select value={selectedVal} onChange={handleChange}>
        <option value="HTML">HTML</option>
        <option value="CSS">CSS</option>
        <option value="REACT">REACT</option>
      </select>
 
      <button onClick={() => SelectChoice()}>선택된 값</button>
 
    </div>
  )
 
}
 
function App(){
 
  return(
    <div>
      <SelectBox />
    </div>
  )
}
 
export default App;
cs

 

 

만약, CSS를 선택하고, onClick을 통해 선택된 값을 확인해보면,

 

 

 

< radio에서의 useState 사용 >

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// radio
function InputRadio(){
  const [radioVal, setRadioVal] = useState("red");
 
  function handleChange(e){
    setRadioVal(e.target.value);
  }
 
  return(
    <div>
      <p>선택된 항목: <strong>{radioVal}</strong></p>
      <input type="radio" value="red" onChange={handleChange} checked={radioVal === "red"/>빨강
      <input type="radio" value="green" onChange={handleChange} checked={radioVal === "green"/>초록
      <input type="radio" value="blue" onChange={handleChange} checked={radioVal === "blue"/>파랑
 
    </div>
  )
}
 
function App(){
  return(
    <div>
      <InputRadio></InputRadio>
    </div>
  )
}
 
export default App;
 
cs

 

이때, "=="는 주소의 비교이고, "==="는 값의 비교이다.

 

초기 결과와 파랑을 선택했을 때의 결과는

 

 

 

<  checkbox에서의 useState 사용 >

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// checkbox
 
const InputCheckBox = () => {
  const [ checkedVal, setCheckedVal] = useState(false); // 체크 안됨
 
  const handleChange = (e) => {
    setCheckedVal(!checkedVal); // 체크가 되거나 안되거나 반대로!
  }
 
  return(
    <div>
      <input type="checkbox" onChange={handleChange} checked={checkedVal} />독서
    </div>
  )
 
}
 
function App(){
  return(
    <div>
      <InputCheckBox/>
    </div>
  )
}
 
export default App;
cs

 

< random 넘버 생성 및 현재 날짜 나타나도록 하기 >

 

참고로,

const [ randState, setRandState ] = useState(0); 부분은

var randNumberState = useState(0); // 배열! 0은 초기값

var randState = randNumberState[0];

var setRandState = randNumberState[1];

로 바꿀 수 있다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//random
function RandAndDate(){
  // const [randState, setRandState] = useState(0);
  var randNumberState = useState(2); // 배열
  var randState = randNumberState[0];
  var setRandState = randNumberState[1];
 
  const [mydate, setMydate] = useState("");
 
  const nowDate = () => {
    setMydate( (new Date()).toString() ); // 현재 날짜
  }
 
 
  return(
    <div>
      <p>Number:{randState}</p>
      <p>Date:{mydate}</p> 
      <input type="button" value="random" 
        onClick=function() {
                      setRandState(parseInt(Math.random()*10))
                    }} />
      <input type="button" value="Date" onClick={nowDate} />              
    </div>
  );
}
 
function App(){
  return(
    <div>
      <RandAndDate/>
    </div>
  )
}
 
 
export default App;
cs

 

 

 

 

 

끝.

'React' 카테고리의 다른 글

[React] file upload & download  (0) 2023.03.30
[React] axios  (0) 2023.03.29
[React] session과 cookie  (0) 2023.03.29
[React] hook - useEffect  (0) 2023.03.29
[React] 리액트 시작 및 기초  (0) 2023.03.29

Theme. 리액트의 시작

 - node.js를 설치했고, vs code를 사용한다.

 

< "터미널"에서 사용되는 명령어! >

1. 프로젝트 생성

npx create-react-app 프로젝트명

 

2. 프로젝트 실행

cd 프로젝트 명

npm start

 

3. 서버 끄기(작업끝내기)

ctrl + c

 

4. 상위 폴더로 이동

cd .. 

 

Theme. 컴포넌트(Component) 만들기

 Component는 사용자 정의  태그이다. 리액트에서의 속성은 prop이라고 한다.

 

 간단하게 Component를 만들고, 동시에 props를 사용해보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function App() {
 
  function Message(){ // component 만드려는 함수의 첫글자는 대문자!
    return <h1>Hello React</h1>
  }
 
  function MessageOne(props){ // props는 가인수
    return ( // 여러 태그를 return 해줄 때는 div태그로 묶어서 작성해야 한다
      <div>
        <h2>Hello {props.name}</h2>
        <p>Hi {props.name}</p>
      </div>
    )
  }
 
  return (
    <div>
      {Message()} {/* 함수 호출 */}
      
      <Message></Message>     {/* component */}
      <Message />             {/* component */}
 
      <MessageOne name="춘향" /> {/* component */}
    </div>
  );
}
 
export default App;
cs

 

실행 결과는 아래와 같다.

 

 

먼저, <Message>, <MessageOne>이라는 태그를 만들기 위해서, 즉 컴포넌트를 만들기 위해서 function 방식을 이용했다. 이때 함수명의 첫글자는 반드시 대문자여야 한다.

<MessageOne name="춘향"> 에서 MessageOne이라는 function이 props을 통해 name="춘향"이라는 object를 받게 된다. 그래서 {props.name}와 같이 사용이 가능하다. key값이 name, 그 value는 "춘향"인 셈.

 

추가적으로, message.js라는 파일을 만들고, 그 안에 MessageTwo라는 function을 만들어 컴포넌트를 만드려고 한다.

외부에서 만들어준 것이기 때문에

import MessageTwo from './message'; 를 작성해줘야 한다. (동일 프로젝트 내에 존재하므로 ./ 이다)

 

먼저, message.js은 다음과 같다.

 

1
2
3
4
5
6
7
8
 
function MessageTwo(props){
  console.log('MessageTwo 호출');
 
  return <div>nice to meet you {props.name</div>
}
 
export default MessageTwo;
cs

 

코드가 추가된 App.js은 다음과 같다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import MessageTwo from './message';
 
function App() {
 
  function Message(){ // component 만드려는 함수의 첫글자는 대문자!
    return <h1>Hello React</h1>
  }
 
  // function MessageOne(props){ // props는 가인수
  //   return <h2>Hello {props.name}</h2>
  // }
 
  function MessageOne(props){ // props는 가인수
    return ( // 여러 태그를 return 해줄 때는 div태그로 묶어서 작성해야 한다
      <div>
        <h2>Hello {props.name}</h2>
        <p>Hi {props.name}</p>
      </div>
    )
  }
 
  return (
    <div>
      {Message()}
 
      <Message></Message>     {/* component */}
      <Message />             {/* component */}
 
      <MessageOne name="춘향" /> {/* component */}
 
      <MessageTwo name="홍두깨" /> {/* component */}
    </div>
  );
}
 
export default App;
 
cs

 

 

그 결과는,

 

 

 

 

Theme. map의 사용

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function App(){
 
  // return (
  //   <div>
  //     <ul>
  //       <li>Apple</li>
  //       <li>Banana</li>
  //       <li>Pear</li>
  //     </ul>
  //   </div>
  // )
 
  // 위와 같은 효과를 나타내기 위해서 map을 사용한다면?
  
  const arr = ["apple""pear""banana"];
// map 사용시 key값을 넣어줘야 하는 규칙에 주의
  const datalist = arr.map((a, index) => (<li key={index}>{index} {a}</li>))
 
  return(
    <div>
      {datalist}
    </div>
  )
 
}
 
export default App;
cs

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function App(){
 
  const members = [
    { "number":1"name":"홍길동""height":172.1 },
    { "number":2"name":"성춘향""height":158.1 },
    { "number":3"name":"일지매""height":181.1 }
  ];
  // map 사용시 key값을 넣어줘야 하는 규칙에 주의
  const memberlist = members.map(function(member, index){
 
    return (
      <tr key={index}>
        <th>{member.number}</th>
        <td>{member.name}</td>
        <td>{member.height}</td>
      </tr>
    )
  });
 
  return (
    <div>
      <table border="1">
        <tbody>
          {memberlist}
        </tbody>
      </table>
    </div>
  )
}
 
export default App;
cs

 

위와 같은 결과를 나타내는 코드를 다시 작성해보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function App(){
 
  const members = [
    { "number":1"name":"홍길동""height":172.1 },
    { "number":2"name":"성춘향""height":158.1 },
    { "number":3"name":"일지매""height":181.1 }
  ];
 
  const memfunc = (member, index) => {
    return (
      <tr key={index}>
        <th>{member.number}</th>
        <td>{member.name}</td>
        <td>{member.height}</td>
      </tr>
    )
  }
 
  const memberlist = members.map(memfunc);
 
  return (
    <div>
      <table border="1">
        <tbody>
          {memberlist}
        </tbody>
      </table>
    </div>
  )
}
 
export default App;
cs

 

 

 

 

그 결과는,

 

 

 

Theme. 이벤트

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function App(){
  
  function btnclick(){
    alert('btnclick');
  }
 
  function inputFunc(e){
    console.log(e.target.value)
  }
 
  return (
    <div>
      <button onClick={ () => btnclick() }>버튼</button>
 
      <button onClick={ () => {console.log('버튼클릭')} }>버튼</button>
 
      <input type="text" onChange={ (event=> {console.log(event.target.value)}} />
     
      <input type="text" onChange={ inputFunc } />
 
      <input type="checkbox" />
    </div>
  )
}
export default App;
cs

 

먼저, (event) => ..... 에서의 event와 inputFunc(e)에서의 e 모두 이벤트 객체이다.

이벤트 객체는 이벤트 상황을 제어할 수 있는 여러가지 정보와 기능이 있다.

이중, 위에서 event.target.value 부분의 의미를 살펴보면,

event.target은 이벤트를 발생시킨 target! 이벤트를 발생시킨 부분! 을 말하는 것이고,

event.target.value는 이벤트를 발생시킨 target의 value를 가져온다는 의미이다.

이때, input 태그를 사용했기 때문에 value를 적은 것이다.

onChange 이벤트이므로 input 부분에 텍스트를 적거나 고칠 때마다 console에 나타내게 된다.

 

 

 

 

 

 

 

'React' 카테고리의 다른 글

[React] file upload & download  (0) 2023.03.30
[React] axios  (0) 2023.03.29
[React] session과 cookie  (0) 2023.03.29
[React] hook - useEffect  (0) 2023.03.29
[React] hook - useState  (0) 2023.03.29

+ Recent posts