no image
React - CORS
1) 서버 애플리케이션 구동 가상 환경을 사용하는 파이썬 프로젝트를 클론한 경우 수행할 작업 a. 프롬프르트를 디렉토리로 이동 python -m venv myvenv myvenv\Scripts\activate b.패키지 설치 pip install -r requirements.txt c.django 프로젝트의 경우 settings.py에 가서 데이터베이스 접속 정보를 수정 d.django 프로젝트의 경우 데이터베이스 반영 작업 수행 python manage.py makemigrations python manage.py migrate e. 실행 python manage.py runserver 0.0.0.0:80 f. 브라우저에서 확인 http://127.0.0.1/todo?userid=Django g. 데이..
2024.01.31
no image
React
1. React 1) SPA (Single Page Application) 하나의 HTML 파일을 이용해서 애플리케이션의 모든 화면을 출력하는 방식 이전의 애플리케이션들은 여러 개의 HTML 파일을 만들어서 화면 전환을 이용해서 여러 콘텐츠를 출력했는데 -> 화면 전환을 하게 되면 이전 내용을 삭제하고 새로운 내용을 출력해야 하기 때문에 깜빡임이 발생하고 -> 네트워크 에러가 발생하게 되면 화면 전체가 에러 페이지를 출력 -> 모바일의 경우는 에러 페이지를 보는 횟수가 증가 해결 방법으로 로컬에 데이터를 저장해서 네트워크 에러가 발생한 경우 로컬의 데이터를 출력 하나의 화면을 여러 컴포넌트로 분할하고 분할한 컴포넌트 별로 별도로 데이터를 요청해서 출력 SPA를 만들기 위한 프레임워크로 널리 사용되는 것이..
2024.01.30

React - CORS

0ㅑ채
|2024. 1. 31. 12:11

1) 서버 애플리케이션 구동

 

가상 환경을 사용하는 파이썬 프로젝트를 클론한 경우 수행할 작업

 

a. 프롬프르트를 디렉토리로 이동

python -m venv myvenv
myvenv\Scripts\activate

 

b.패키지 설치

pip install -r requirements.txt

 

c.django 프로젝트의 경우 settings.py에 가서 데이터베이스 접속 정보를 수정

 

d.django 프로젝트의 경우 데이터베이스 반영 작업 수행

python manage.py makemigrations
python manage.py migrate

 

e. 실행

python manage.py runserver 0.0.0.0:80

 

f. 브라우저에서 확인

http://127.0.0.1/todo?userid=Django

 

g. 데이터 입력

desc todoapplication_todo ;

desc todoapplication_todo ;

 

Null 여부를 봤다. 데이터를 넣어야 한다. 

auto_increment가 있으니 id는 안넣어도 된다.

다 입력하고 커밋!

COMMIT;

 

id에 따라 다른정보들이 조회됨

 

 

2) 클라이언트 애플리케이션의 App.js 파일에 데이터를 요청하는 코드 추가

  componentDidMount(){
    //ajax 요청 객체 생성
    let request = new XMLHttpRequest()
    //요청 준비
    request.open('GET', "http://127.0.0.1/todo?userid=Django")
    //요청
    request.send('')
    //응답 처리
    request.addEventListener('load', () => {
      //json 데이터 출력
      console.log(request.responseText)
    })
  }

 

구동 http://localhost:3000/

 

CORS Policy 에러가 출력

  • 서버 애플리케이션은 127.0.0.1:80으로 실행 중이고
    클라이언트 애플리케이션은 localhost(127.0.0.1):3000으로 실행중

 

SOP (동일 출처 정책)

  • ajax나 fetch api는 브라우저의 동일 출처 정책에 따라 자신과 동일한 도메인의 데이터만 받아올 수 있다.
  • 동일 도메인이란 IP주소와 포트번호까지 일치하는 것을 의미한다.
  • 서버 애플리케이션과 클라이언트 애플리케이션을 따로 구현하면 SOP 정책에 따라 ajax나 fetch api를 이용해서는 서버의 데이터를 사용할 수 없다.
  • 서버 애플리케이션에서 요청이 가능한 클라이언트 애플리케이션의 도메인을 등록
  • 서버 애플리케이션을 만들 때 CORS 설정을 확인해두자!

* React의 경우는 react의 설정 파일에 설정을 해도 CORS 설정이 가능하다.

* react가 node.js 플랫폼 위에서 동작하는데 node.js가 C/C++이라서 proxy를 이용해 react에 데이터를 넘겨줄 수 있다.

 

 

3) Django의 CORS 설정

a. cors 관련 패키지 설치

pip install django-cors-headers

 

b. django 프로젝트의 settings.py 파일: 애플리케이션 등록

#애플리케이션 등록
INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "todoapplication",
    "corsheaders", #여기
]

 

c. django 프로젝트의 settings.py 파일 : MIDDELWARE 맨 앞에 등록

MIDDLEWARE = [
    "corsheaders.middleware.CorsMiddleware", #여기
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
]

 

d. django 프로젝트의 settings.py 파일: 허용할 LIST 등록

CORS_ORIGIN_WHITELIST =['http://127.0.0.1:3000', 'http://localhost:3000']
CORS_ALLOW_CREDENTIALS =True
  • 허용할 도메인 등록 - 지금은 react라서 3000번 등록
  • 실제로는 배포하는 도메인을 등록!

구동 시 CORS Policy 에러 해결

 

클라이언트 App.js를 수정

  componentDidMount(){
    //ajax 요청 객체 생성
    let request = new XMLHttpRequest()
    //요청 준비
    request.open('GET', "http://127.0.0.1/todo?userid=Django")
    //요청
    request.send('')
    //응답 처리
    request.addEventListener('load', () => {
      //json 데이터 출력

      //JSON 문자열을 데이터로 변환
      let data = JSON.parse(request.responseText);
      console.log(data)
      //서버에서 받아온 데이터를 state에 대입해서 화면에 출력
      this.setState({items:data.list})
    })
  }

 

 

 

 

 

 

'JavaScript' 카테고리의 다른 글

React  (1) 2024.01.30

React

0ㅑ채
|2024. 1. 30. 17:49

1. React

 

1) SPA (Single Page Application)

  • 하나의 HTML 파일을 이용해서 애플리케이션의 모든 화면을 출력하는 방식
  • 이전의 애플리케이션들은 여러 개의 HTML 파일을 만들어서 화면 전환을 이용해서 여러 콘텐츠를 출력했는데
    -> 화면 전환을 하게 되면 이전 내용을 삭제하고 새로운 내용을 출력해야 하기 때문에 깜빡임이 발생하고
    -> 네트워크 에러가 발생하게 되면 화면 전체가 에러 페이지를 출력
    -> 모바일의 경우는 에러 페이지를 보는 횟수가 증가
  • 해결 방법으로 로컬에 데이터를 저장해서 네트워크 에러가 발생한 경우 로컬의 데이터를 출력
    하나의 화면을 여러 컴포넌트로 분할하고 분할한 컴포넌트 별로 별도로 데이터를 요청해서 출력
  • SPA를 만들기 위한 프레임워크로 널리 사용되는 것이 angular, react, vue 입니다.
  • angular는 구글이 만든 것으로 공식적으로 더 이상 업데이트를 하지 않는다고 발표를 했습니다.
  • 현재 국내 플랫폼 기업이나 중소 기업은 react를 선호하는데 vue를 사용하는 곳도 있습니다.

 

 

2) React

2013년, Facebook에서 발표한 SPA를 구현하기 위한 오픈소스 자바스크립트 프레임워크

  • 새로운 문법 사용: 가상 DOM과 JSX
  • 출력이 빠름: 게임 엔진의 출력 방식을 이용, 가상의 DOM을 메모리에 배치하기 떄문
  • 컴포넌트 기반
    • 태그
      화면에 보여지는 개체 <div>
    • 컴포넌트
      하나의 영역을 나타내기 위한 태그와 코드의 집합
      자체적으로 데이터를 가질 수 있고, 데이터가 변경되면 자동으로 재출력 (새로고침 필요 X)
      미리 구조를 만들어두고 다시 출력할 때는 변경된 부분만 다시 출력
  • 프레임워크가 제공하는 기능을 그대로 사용
    • 클래스가 충분한 기능을 제공해주기 때문에 클래스를 이용해서 인스턴스를 만들어서 바로 사용
    • ex. 프레임워크가 Template라는 클래스를 제공하면
      template = new Template()
  • 프레임워크가 제공하는 기능을 상속받아서 재정의해서 사용
    • 클래스가 충분한 기능을 제공해주지 않아서 내가 기능을 추가해서 사용
    • 상속을 받으면 상위 클래스의 모든 것을 하위 클래스가 물려받음
  • React에서는 Component라는 클래스가 Component의 기능은 전부 가지고 있는데 화면에 아무것도 출력하지 않는다.
    React.Component로부터 상속을 받고 render라는 메서드를 재정의해서 return 값을 출력하도록 설계

 

 

React-native

- 모바일 앱을 만들 수 있다. 

- 안드로이드와 애플 환경에서 모두 사용할 수 있게 코드를 바꿔준다. 

 

Figma

- 디자인을 리액트 코드로 바꿔준다.

 

 

3) 설치

node.js 설치

- node.js를 자바스크립트로 애플리케이션을 개발하기 위한 플랫폼이다. (프레임워크 아님)

- 설치확인: node --version

 

패키지 관리자: npm과 yarn

- package.json 파일에 의존성을 설정하고 node.modules 디렉토리에 패키지 저장

- git hub에 업로드 할 때 node_modules는 할 필요 없음. package.json만 있으면 빌드를 다시 해서 설치 가능

npm install --location=global yarn

- 설치 확인: yarn --version

 

 

4)React 프로젝트 생성 및 실행

생성

yarn create react-app 앱이름(myapp)

 

실행

#myapp 디렉토리에서
yarn start

yarn 없이 실행: npm start

 

 

 

5) Comonent를 화면에 출력

Component: 화면에 출력되는 독립적인 개체

 

src 디렉토리에 ToDo.jsx 

확장자는 js 도 상관없지만 react 컴포넌트 파일이라는 것을 알려주기 위해서 jsx 로 설정

import React from "react";

//react에서 컴포넌트 클래스를 만들기 위해 Component로부터 상속 받기
class ToDo extends React.Component {
    //화면에 출력할 내용을 리턴하는 메소드
    render(){
        return(
            <div className="ToDo">
                <input type="checkbox" id="todo0" name="todo0" value="todo0"/>
                <label for="todo0">ToDo 컴포넌트 만들기</label> 
            </div>
        )
    }
}
  • id: 자바스크립트에서 태그를 구별해서 가져오기 위한 값 (중복 불가)  document.getElementById
  • class: react에선 className. css에서 동일한 디자인을 적용하기 위한 이름 (중복 가능)  document.getElementByClassName
  • name: 클라이언트가 서버로 전송할 때 이름 (중복 가능. checkbox, select 등)
  • value: 값
  • label: for="id"  글자를 눌러도 체크가 된다. 

메인 페이지의 역할을 수행하는 App.js 수정해서 ToDo 컴포넌트 출력

import './App.css';

import React from "react"
import ToDo from "./ToDo" #파일 이름이라는 것을 강조하기 위해 ./ 사용, 없어도 됨

function App() {
  return (
    <div className="App">
      <ToDo />
    </div>
  );
}

export default App;
  • export default App; 이 없을 경우 에러
    ERROR in ./src/index.js 12:33-36
    export 'default' (imported as 'App') was not found in './App' (module has no exports) 
  • javascript는 기본적으로 private이라서 그렇다.
  •  react는 App.js 파일이 전체 화면을 출력하는 파일
     App.js에 작성한 내용이 출력
     react는 반드시 하나로 묶어서 출력해야 함

성공!

더보기

연습

 

src에 Sample.jsx 생성

import React from "react"

class Sample extends React.Component{
    render(){
        return(
            <div className="Sample">
                <p>안녕하세요</p>
            </div>
        )
    }
}

export default Sample;

 

App.js

import './App.css';
import React from 'react';
import ToDo from './ToDo';
import Sample from './Sample';

function App() {
  return (
    <div className="App">
      <ToDo />
      <Sample/>
    </div>
  );
}

export default App;

 

 

6) 컴포넌트에서 데이터를 사용하는 방법

  • props 속성 : 상위 컴포넌트에서 넘겨주는 데이터
    큰 화면에서 작은 화면으로 넘어갈 때 전달해주는 데이터
    내가 쓸 데이터를 내가 만들어서 준다. 
  • state 상태 : 컴포넌트 내부에서 사용하는 데이터
    react는 props나 state에 변화가 생기면 화면을 다시 출력
  • context : 글로벌·전역변수, 모든 컴포넌트에서 사용할 수 있는 데이터
    ex. 로그인 기능
  • redux : 전역 데이터를 만드는 외부 라이브러리
  • Entry 포인트 : React는 시작점이 App.js

 

 

7) props와 state 사용

ToDo.jsx

import React from "react"

class ToDo extends React.Component{

    //생성자
    constructor(props){
        super(props); //상위 클래스에서 넘겨준 모든 props를 현재 클래스에 저장
        //state 생성 - item이라는 이름으로 props 중에서 item이라는 값을 state로 저장
        //props는 상위 컴포넌트에서 전달한 데이터라서 읽기는 가능하지만
        //수정이나 삭제가 안되므로 수정이나 삭제를 하고자 하는 경우는 
        //state로 변환을 해야 합니다.
        this.state = {item:props.item}
    }

    render(){
        return(
            <div className="ToDo">
                <input type="checkbox" 
                    id={this.state.item.id} 
                    name={this.state.item.id} 
                    value={this.state.item.done}/>
                <label id={this.state.item.id}>{this.state.item.title}</label> 
            </div>
        )
    }
}

export default ToDo;

  • 그런데 현재 상위 컴포넌트가 없는 상태라서 item.id, item.done, item.title을 묶을 수 있는 클래스가 필요하다.

 

App.js 수정 > ToDo.jsx 파일에 props 전달

import './App.css';
import React from 'react';
import ToDo from './ToDo';

class App extends React.Component {
  constructor(props){
    super(props)
    //3개의 객체를 가진 배열을 생성
    //this.state.item = {item:{id:0, "title":"Hello React", "done":true}}
    this.state = {item:{id:0, "title":"Hello React", "done":true}}
  }

  render(){
    return(
      <div>
        {/* Todo에게 item이라는 이름으로 데이터 전달 */}
        <ToDo item={this.state.item} />
      </div>
    )
  }
}

export default App;
  • App.js에 this.state.item이라는 이름으로 데이터 생성
  • props의 데이터를 ToDo에게 전달
  • 상위 클래스: React.Component
    상위 컴포넌트(부모): App
    하위 컴포넌트(자식): Todo
    하위 클래스: App

배열이나 리스트를 순회하면서 작업을 수행하는 경우

map

데이터를 변환해주는 함수

함수를 대입해서 함수에 데이터를 순서대로 대입해서 리턴한 결과를 모아 다시 배열이나 리스트로 리턴해주는 함수

 

filter

데이터를 필터링해주는 함수

boolean을 리턴하는 함수를 대입해서 데이터를 순서대로 대입하고 return 값이 true인 데이터만 모아 다시 배열이나 리스트로 리턴해주는 함수

 

reduce

계산하고 리턴해주는 함수

연산 후 리턴하는 함수를 대입해서 데이터를 순서대로 대입,

return 값을 가지고 다음 함수 호출의 매개변수로 활용해서 결과를 하나의 값으로 리턴해주는 함수

 

 

App.js

import './App.css';
import React from 'react';
import ToDo from './ToDo';
// import Sample from './Sample';

class App extends React.Component {
  constructor(props){
    super(props)
    //this.state.time = {item:{id:0, "title":"Hello React", "done":true}}
    this.state = {items:[ {id:0, "title":"Hello React", "done":true}, 
                          {id:1, "title":"vue", "done":false}, 
                          {id:2, "title":"angular", "done":false}]
                  }
  }

  render(){
    //배열을 순회하면서 출력할 내용을 생성
    //item은 배열을 순회할 때 각각의 데이터이고 idx는 인덱스
    //배열을 순회하면서 출력물을 만들 때는 key를 설정
    //key를 설정하지 않으면 출력에는 문제가 없지만 콘솔에 에러가 출력
    let display = this.state.items.map((item, idx) => ( //(아이템, 인덱스)
        <ToDo item={item} key={item.id} />
    ));
    
    return(
        <div className="App">
            {display}
        </div>
    )
  }
}

export default App;

 

ToDo.jsx

...
render(){
        return(
            <div className="ToDo">
                <input type="checkbox" 
                    checked={this.state.item.done}/>
                <label id={this.state.item.id}>{this.state.item.title}</label> 
            </div>
        )
    }
...

 

 

8 ) material UI를 이용한 디자인 변경

 

도큐먼트 https://mui.com/

  • material design: 구글이 제시한 PWA(모바일 앱과 같은 웹 UI)를 위한 디자인 방식
  • material-UI 패키지: 구글의 material design 적용한 리액트 패키지

 

패키지 설치

npm install --save --legacy-peer-deps @material-ui/core
npm install --save --legacy-peer-deps @material-ui/icons
  • node가 아니라 application에 설치 (node_modules)

ToDo.jsx

import React from "react"

import {
    ListItem,
    ListItemText,
    InputBase,
    Checkbox
}from "@material-ui/core"

class ToDo extends React.Component{
    constructor(props){
        super(props);
        this.state = {item:props.item}
    }

    render(){
        //자주 사용하는 데이터를 짧게 사용하기 위해 다른 변수에 대입
        const item = this.state.item;
        return(
            <ListItem>
                <Checkbox checked={item.done} />
                <ListItemText>
                    <InputBase
                        InputProps={{"aria-label":"naked"}}
                        type="text"
                        id={item.id}
                        name={item.id}
                        value={item.title}
                        multiline={true} //여러줄로 생성
                        fullWidth={true} //화면에 꽉차게
                    />
                </ListItemText>
            </ListItem>
        )
    }
}

export default ToDo;

 

App.js

import './App.css';
import React from 'react';
import {Paper, List} from "@material-ui/core"

class App extends React.Component {
  constructor(props){
    super(props)
    this.state = {items:[ {id:0, "title":"Hello React", "done":true}, 
                          {id:1, "title":"vue", "done":false}, 
                          {id:2, "title":"angular", "done":false}]
                  }
  }

  render(){
    var display = this.state.items.length > 0 && (//데이터가 있을 때(True)만 실행
      <Paper style={{margin:16}}>
        <List>
          {this.state.items.map((item, idx) => (
            <ToDo item={item} key={idx} />
          ))}
        </List>
      </Paper>
    )
    
    return(
        <div className="App">
            {display}
        </div>
    )
  }
}

export default App;

 

 

 9) 하나의 문자열을 입력하는 컴포넌트 

src 디렉토리에 컴포넌트로 사용할 파일 추가 : AddToDo.jsx

import React from "react"

import {TextField, Paper, Button, Grid} from "@material-ui/core"

class AddToDo extends React.Component{
    constructor(props){
        super(props);
    }

    render(){
        return(
            <Paper style={{margin:16, padding:16}}>
                <Grid container>
                    <Grid xs={11} md={11} item style={{paddingRight:16}}>
                        <TextField placeholder="여기에 작성하시오!!!" fullWidth />
                    </Grid>
                    <Grid xs={1} md={1} item>
                        <Button fullWidth color="secondary">
                            +
                        </Button>
                    </Grid>
                </Grid>
            </Paper>
        )
    }
}

export default AddToDo

 

App.js

import './App.css';
import React from 'react';
import {Paper, List, Container} from "@material-ui/core"
import AddToDo from './AddToDo';

class App extends React.Component {
  ...
  }

  render(){
    ...
    )
    
    return(
        <div className="AppToDo">
          <Container maxWidth="md"> 
            <AddToDo />
            {display}
          </Container>
        </div>
    )
  }
}

export default App; 안녕하세요~ 반가워용~ 이 자리 장비가 좋아서 코딩이 잘되네요~ 100점 드립니다~~~!!!!!
  • 늘어나거나 줄어들 때 비율을 유지하려면, 전체 화면 크기를 일정한 숫자로 지정하고 비율로 추정할 수 있다.
  • defualt는 12 (n/12)

 

 

10) 수정 화면에서 문자열을 입력하고 Enter나 + 버튼을 누르면 입력한 내용을 추가해서 화면에 반영

함수는 일급 객체: 파이썬과 자바스크립트가 여기에 해당

- 함수도 하나의 자료형

- 함수를 이용해 변수 생성, 매개변수로 대입, 리턴 가능 

 

App.js

import './App.css';
import React from 'react';
import {Paper, List, Container} from "@material-ui/core"
import AddToDo from './AddToDo';

class App extends React.Component {
  ...
  }

  add = (item) => {
    //react는 props는 수정할 수 없고
    //state는 수정이 가능하지만 원본을 직접 수정하는 것은 불가
    //setState 메소드를 이용해서만 수정이 가능

    //배열에 데이터를 추가하기 위해서 state의 배열을 복사
    const thisItems = this.state.items;

    //item의 id와 done 값을 설정 - title만 입력하기 때문
    item.id = "ID_" + thisItems.length;
    item.done = false;

    //복사한 데이터에 추가
    thisItems.push(item)
    //복사한 데이터를 다시 state에 적용
    this.setState({items:thisItems});
  }

  render(){
    ...
    )
    
    return(
        <div className="AddToDo">
          <Container maxWidth="md"> 
            <AddToDo add={this.add}/>
            {display}
          </Container>
        </div>
    )
  }
}

export default App;

 

AppToDo.jsx 수정해서 삽입 구현

...
//TextField에서 값을 입력할 때마다 호출되는 이벤트 리스너
    onInputChange = (e) => {
        //state.title에 입력한 내용을 대입
        this.state.item.title = e.target.value
    }
...

WARNING in [eslint]
src\AddToDo.jsx
  Line 20:9:  Do not mutate state directly. Use setState()  react/no-direct-mutation-state

  • 복사본을 만들어서 저장해줘야 한다. 

AppToDo.jsx

import React from "react"
import {TextField, Paper, Button, Grid} from "@material-ui/core"

class AddToDo extends React.Component{

    constructor(props){
        super(props);

        //App.js 파일에서 넘겨준 메소드를 add에 저장
        this.add = props.add;

        //입력한 문자열을 저장하기 위한 속성을 생성
        this.state = {item:{title:""}}
    }

    //TextField에서 값을 입력할 때마다 호출되는 이벤트 리스너
    onInputChange = (e) => {
        //state.title에 입력한 내용을 대입
        const thisItem = this.state.item
        thisItem.title = e.target.value
        this.setState({item:thisItem})
        console.log(this.state.item.title)
    }

    //+버튼을 눌렀을 때 호출되는 이벤트 리스너
    onButtonClick = (e) => {
        //배열에 데이터 삽입하는 함수 호출
        this.add(this.state.item)
        //텍스트 필드 초기화
        this.setState({item:{title:""}})
    }

    //Enter를 누르면 호출되는 이벤트 리스너
    enterKeyEventHandler = (e) => {
        if(e.key === "Enter"){
          this.onButtonClick();
        }
    }

    render(){
        return(
            <Paper style ={{margin:16, padding:16}}> 
                <Grid container>
                    <Grid xs={11} md={11} item style={{paddingRight:16}}>
                        <TextField placeholder ="여기에 작성하시오!" fullWidth
                        onChange={this.onInputChange} value={this.state.item.title}
                        onKeyPress={this.enterKeyEventHandler}/>
                    </Grid>
                    <Grid xs={1} md={1} item>
                        <Button fullWidth color="secondary" onClick={this.onButtonClick}>
                            +
                        </Button>
                    </Grid>
                </Grid>
            </Paper>
        );
    }
}

export default AddToDo

 

 

 

 11) 삭제 구현

import React from "react"

import {
    ListItem,
    ListItemText,
    InputBase,
    Checkbox,
    IconButton, //여기
    ListItemSecondaryAction,
}from "@material-ui/core" 

import DeleteOutlined from "@material-ui/icons/DeleteOutlined" //여기

class ToDo extends React.Component{

    //생성자
    ...
    
    render(){
        const item = this.state.item;
        return(
            <ListItem>
                <Checkbox checked={item.done} />
                <ListItemText>
                    < ... />
                </ListItemText>
                <ListItemSecondaryAction> 
                    <IconButton aria-label="Delete ToDo">
                        <DeleteOutlined />
                    </IconButton>
                </ListItemSecondaryAction>
            </ListItem>
        )
    }
}

export default ToDo;

 

데이터를 전달받는 방식보다
함수를 전달받는 방식이 더 좋다.

 

 

12) 삭제를 처리할 메소드를 App.js에 생성

  ...
  
  //삭제를 위한 메소드
  delete = (item) => {
    //state나 props의 데이터는 직접 편집이 불가
    const thisItems = this.state.items;

    //복사본에서 item을 제거
    //filter 함수는 리턴 타입이 boolean 함수를 매개변수로 받아서
    //리턴 결과가 true인 데이터만 모아서 배열로 리턴하는 함수
    //아닌 것만 골라내서 빼는 방법
    const newItems = thisItems.filter((e) => e.id !== item.id)
    this.setState({items:newItems})
  }
  
  render(){
    var display = this.state.items.length > 0 && (
      <Paper style={{margin:16}}>
        <List>
          {this.state.items.map((item, idx) => (
            <ToDo item={item} key={idx} delete={this.delete} /> /*여기 추가*/
          ))}
        </List>
      </Paper>
    )

...

 

 

 

13) ToDo.jsx 파일에서 삭제 아이콘을 누르면 삭제

import React from "react"

import {
    ...
}from "@material-ui/core"

import DeleteOutlined from "@material-ui/icons/DeleteOutlined"

class ToDo extends React.Component{

    //생성자
    constructor(props){
        super(props);
        
        //state 생성 - item이라는 이름으로 props 중에서 item이라는 값을 state로 저장
        this.state = {item:this.props.item}

        //App.js에서 넘겨준 삭제 함수를 현재 클래스의 데이터로 변환
        this.delete = this.props.delete
    }

    //삭제 버튼을 누를 때 호출될 이벤트 핸들러
    deleteEventHandler = (e) => {
        this.delete(this.state.item)
    }

    render(){
        const item = this.state.item;
        return(
            <ListItem>
                <Checkbox checked={item.done} />
                <ListItemText>
                    ...
                    />
                </ListItemText>
                <ListItemSecondaryAction>
                    <IconButton aria-label="Delete ToDo" onClick={this.deleteEventHandler}> //여기
                        <DeleteOutlined />
                    </IconButton>
                </ListItemSecondaryAction>
            </ListItem>
        )
    }
}

export default ToDo;

 

 

 

4) App.js 파일에서 더미 데이터 전부 삭제

class App extends React.Component {
  constructor(props){
    super(props)
    this.state = {items:}
  }

하면 다시 화면 초기화

 

 

 

 

 

 

'JavaScript' 카테고리의 다른 글

React - CORS  (0) 2024.01.31