새로고침을 하고싶지 않다면,

절대, <a> 링크를 써서는 안 된다.

<a>링크를 써서 태그된 부분을 클릭하게 되면,

이동할때 페이지를 새로고침하면서 로딩하게 된다.

새로고침할떄, 깜빡거리는 현상(Blink)이 보기 싫다면,

리액트 라우터에 존재하는 Link 컴포넌트를 써야한다.

Link를 사용하면 페이지를 새로고침해서 불러오지 않고,

주소창을 변경하며 원하는 라우트로 화면을 전환하게 된다.

Link와 유사한 비슷하지만 추가적인 기능을 갖은 컴포넌트도 존재한다.

이름은 NavLink

이 컴포넌트는 현재 주소와 해당 컴포넌트의 목적지 주소가 일치한다면,

특정 스타일을 지정할 수 있다.

CSS 스타일 지정 : activeStyle으로 지정.

CSS 클래스 지정 : activeClassName으로 지정.


하지만, Link나 NavLink의 경우 링크를 걸고 단순히 클릭했을 때, 

이동시키는 기능이라 자바스크립트에서 페이지를 이동하기에는 한계가 있다.

이 경우에는 라우트로 사용되는 컴포넌트가 받는 props 중 history 객체를,

그 history 객체 중 push 함수를 활용하면 된다.

history.push('/about/intro');


Posted by sungho88
,

yarn run v1.10.1

error Couldn't find a package.json file in "C:\\Users\\Jang\\Desktop\\routertest"


이건 뭐지 


만들자마자 실행했는데 왜 에러지?

한참을 찾았는데

황당한 이유였다.

리액트 라우터 관련 예제를 실습해보기 위해

routertest라는 폴더를 하나 만들고 그 곳에다가,

create-react-app react-router-tutorial

이라고 입력했다.

그랬더니

routertest 폴더 안에 react-router-tutorial 폴더를 만들고 그 안에 리액트가 설치되었다.


즉, routertest 폴더에서 아무리

npm start

또는

yarn start를 한다고 실행이 될까?

리액트는 하위 폴더인 react-router-tutorial에 설치되었는데.

따라서,

$ cd react-router-tutorial

를 통해 react-router-tutorial 폴더로 이동한 뒤에

실행을 시켜야 작동을 하게 된다.

황당한 실수.

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

참고로, 

생성한 routertest 폴더에 리액트를 설치하려면 어떻게 할까?

create-react-app 뛰에 점(.)만 붙여주면 된다. 

붙이지 말고 한 칸 띄어서..

create-react-app .

으로 하면, 해당 디렉토리에 리액트가 설치된다.

이상으로 어이없는 문제 하나 해결!

위는 routertest에서 실행했을 때, 에러 발생. 

왜냐? 설치는 하위 폴더인 react-router-tutorial에 설치되었기 때문이다.




여기에 이렇게!!!!



Posted by sungho88
,

SPA = Single Page Application의 약자이다.

말 그대로, 페이지가 하나인 어플리케이션이다.

예전에는 어떤 웹 어플리케이션을 만들때, 여러 페이지로 구성되었다.

A.html , B.html, C.html , D.html ....

그리고 페이지를 로딩할때마다 서버에서 리소스를 전달받아와서 렌더링했다.

즉, 웹 어플리케이션 뷰를 서버에서 담당했었다.

하지만, 규모가 커지고 사용자와의 상호 작용이 많아짐에 따라, 

데이터 정보 전송 과부화로 인한 속도 저하 등 문제점이 생기게 되었다.

그래서 요즘 나오는 라이브러리 또는 프레임워크는 뷰 렌더링을 서버가 아닌 웹 브라우저가 담당한다.

 

예전에는 페이지를 요청할때마다 서버로 접속하여 받아왔기 때문에, 페이지가 매번 새로고침 되었지만,

SPA의 경우 서버에서 제공하는 페이지가 한 개이며, 

로딩을 한 번 하고난 후에는 브라우저 내에서 나머지 페이지들을 정의하여 보여준다.

일단, 첫 번째 페이지를 받아온 후 다른 페이지로 이동할때는 서버에 새로운 페이지를 요청하는게 아니라,

새 페이지에서 필요한 데이터만 받아와서 다른 종류의 뷰를 만든다.

주소에 따라 다른 뷰를 보여주는 것을 라우팅(Routing)이라 부른다. 

리액트에서는 이 라우팅 기능이 기본으로 내장되어 있지 않기 때문에, 

라우팅 관련 라이브러리인 react-router를 설치해서 구현할 수 있다.

이 라이브러리는 클라이언트 사이드에서 진행하는 라우팅 과정을 쉽게 해준다.

리액트 라우터를 사용하면 페이지 주소를 변경했을 때, 주소에 따라 다른 컴포넌트를 렌더링 해준다.

또한, 주소 정보(파라미터, URL 쿼리 등)를 컴포넌트의 props에 전달하여 컴포넌트 단에서

주소 상태에 따라 다른 작업을 하도록 설정한다.

 

[SPA 단점]

앱 규모가 커질수록 자바스크립트 파일 크기도 너무 커지게 된다는 것이 단점이다.

페이지를 로딩할 때, 실제로 방문하지 않을 수도 있는 페이지와 관련된 컴포넌트 코드도 불러오기 때문.

 

(이후 추가할 예정...)

 

 

 

벨로포트님 블로그 참고했습니다. 추천 100번 합니다!

 

https://www.10000duck.com/ducks/38

 

10000duck - 안전을 위한 법이 우리의 보금자리를 위협합니다.

온라인 모금함을 통해 기부하세요.

www.10000duck.com

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Posted by sungho88
,

[리액트 개발 시, state 관리의 문제점]


상태(state)가 업데이트되면 컴포넌트가 렌더링된다.


그리고, 이 컴포넌트의 하위 컴포넌트들은 모두 자동으로 리-렌더링된다.


리-랜더링이 된다는 말은 로딩 시간이 더욱 길어진다는 뜻이다. 불필요한 렌더링은 막아야 한다.


소규모 프로젝트에서는 이러한 불필요한 렌더링을 shouldComponentUpdate를 구현하여  방지할 수 있다.


이 shouldComponentUpdate 함수를 사용하면 render()함수를 실행시키지 않기때문에 렌더링을 하지 않는다.


하지만, 프로젝트가 대규모가 된다면 트리 구조 상 너무 복잡해지며, 일일히 잡아주기도 한계가 있다. 


또한, 하나의 상위 컴포넌트에서 모든 상태(state)를 관리한다면,


2단계 컴포넌트 자신은 필요가 없는데, 3단계 자식 컴포넌트 때문에 갖고 있어야 한다.


따라서, 불필요한 props의 개수가 많아지게 된다.


여러 컴포넌트를 거처서 props를 전달하는 것은 비효율적이며, 가독성이 떨어지게 된다.


이러한 다양한 문제점을 방지하기 위해 Redux를 사용한다.


리액트에서 컴포넌트 트리를 정리해보면 다음과 같다.




리액트는 이러한 계층 구조로 이루어진다. 또한, 루트 컴포넌트(App.js)에서 기본적으로 모든 상태를 관리한다.


그래서, App.js 컴포넌트의 상태를 업데이트하면 App 컴포넌트뿐만 아니라, 모든 하위 컴포넌트들도 리렌더링된다.

 

리액트 프로젝트 환경에서는 부모 컴포넌트(App.js)를 거처야 서로 소통이 가능하다.


부모 컴포넌트를 거치지 않고 직접 소통할 수는 있지만 코드가 꼬여버리기 때문에(스파게티 소스)


절대 그렇게 해서는 안 된다. 그러다보니, 위에서 말한 것과 같이 불필요한 props가 발생되는 것이다.


여러 컴포넌트를 거쳐서 props를 전달하는 것은 비효율적이다.


- 작업할 때, 가독성이 떨어지며,

- props의 개수가 너무 많아질 수도 있다.



만약, G에서 필요한 값을 위해서 App.js B와 C에 쓰이지도 않는 props를 G를 위해 선언해야 한다.


App.js에서는, <B name={"SUNGHO"} />


B에서는 , <C name={this.props.name} />


C에서는, <G name={this.props.name} />


이렇게 보내줘야 G에서 받아서 쓰는 것이다.


그런데, 만약 name 속성을 바꾼다면?  또 3개의 파일을 각각 열어서 name을 일일히 바꿔줘야 한다.


복잡해질수록, 유지보수 역시 최악으로 간다.



[리덕스 개념]


리덕스가 없는 리액트는 상태(state)를 컴포넌트 자신이 자체적으로 상태 관리한다.


반면, 리덕스를 사용한 리액트는 상태 관리의 로직을 컴포넌트 외부에서 관리하는 것이다.


즉, 상태를 좀 더 효율적으로 관리하는데 사용하는 상태 관리 라이브러리라고 할 수 있다.


리덕스를 사용하면 스토어(Store)라는 객체 내부에 상태에 대한 데이터를 담아 관리할 수 있게 된다.

스토어는 리액트 개발 프로젝트상의 상태에 대한 데이터값들을 내장하고 있다.

정리

리덕스를 사용하게되면,

1. 스토어에서 모든 상태 관리를 한다.

2. 상태에 어떤 변화를 일으켜야할 때는 액션스토어에 전달한다. 
    액션 = 객체 형태이고, 상태를 변화시킬 때 이 객체를 참조해서 변화를 일으킨다

3. 액션을 전달하는 과정을 디스패치(Dispatch)라 한다.

4. 스토어가 액션을 받으면 리듀서가 전달받은 액션을 기반으로 상태를 어떻게 변화시킬지 정한다.
    액션을 처리하면 새 상태를 스토어에 저장한다.

5. 스토어의 값이 바뀌면 스토어를 구독(subscribe)하고 있는 컴포넌트에 바로 전달한다.
   이렇게 부모 컴포넌트로 props를 전달하는 작업은 생략하며, 
   리덕스에 연결하는 함수를 사용하여 컴포넌트를 스토어에 구독시킨다.





스토어가 생기면,


G는 더이상 App.js -> B -> C 순으로 props를 받아서 쓰지 않고, 다이렉트로 스토어에 값을 달라고 요청을 한다.


이것을 "G 컴포넌트가 스토어에 구독(Subscribe)한다"고 말할 수 있다.


구독을 하게되면, 나중에 스토어 안에 있는 상태 변동이 있다면, 구독하고 있는 컴포넌트에 바로 전달한다.



만약, B에서 뭔가 이벤트가 발생해서 상태를 변경(Update)하고자할 때는,


dispatch라는 함수를 통해서 액션을 스토어에게 전달한다.


액션(Action)은 객체 형태로 되어 있으며, 상태를 변화시킬때 이 객체를 참조하여 변화를 일으킨다.


이 액션을 전달하는 과정을 디스패치(Dispatch)라 부른다.


스토어가 액션을 받으면 리듀서가 전달받은 액션을 기반으로 상태를 어떻게 변경해야 할 지 정한다.


액션을 처리하게 되면 새 상태를 스토어에 저장한다.


정리


1. 스토어 : 리액트 프로젝트 내 상태 값들을 내장하고 있는 객체.


2. 액션 : 상태 변화를 일으킬 때 참조하는 객체.


3. 디스패치 : 액션을 스토어에 전달하는 것을 의미함.


4. 리듀서 : 상태를 변화시키는 로직이 있는 함수.


5. 구독 : 스토어 값이 필요한 컴포넌트들은 스토어를 구독.



리덕스는 리액트에 종속적(의존적)이지 않다.


즉, 리액트를 사용하지 않아도 리덕스를 사용할 수 있다.


<액션 & 액션 생성 함수>

[액션]
액션은 스토어에서 상태 변화를 일으킬 때 참조하는 객체이며, 이 객체는 반드시 type값이 있어야 한다.

type만 고정이며, 다른 것들은 유동적이므로 자유롭게 선택해 사용하면 된다.

액션 타입은 해당 액션이 어떤 작업을 하는 액션인지 정의한다.(대문자와 밑줄(_) 조합으로 생성)

하지만, 액션을 새로 만들때마다 직접 객체를 만든다면 액션 형식을 모두 알아야하므로 불편하다.

따라서, 액션을 만들어주는 함수를 사용하는데, 이를 액션 생성 함수라 부른다.

[액션 생성 함수]

1. 먼저 액션 타입을 상수값으로 정의한다.

const INCREMENT;
const POINT_NUMBER;

2. 액션 생성 함수를 생성한다.

const increment = () => ({
type: INCREMENT
})

const point = () => ({
type: POINT_NUMBER
})

type외에 다른 값이 들어가야 한다면, 파라미터에 넣으면 된다.

const point = (name) => ({
type: POINT_NUMBER
})


const INCREMENT = 'INCREMENT';
const POINT_NUMBER = 'POINT_NUMBER';


const increment = () => ({
type: INCREMENT
})


const point = (point) => ({
type: POINT_NUMBER,
point: point
})


console.log(increment());
console.log(point(19));


위에서 생성한 액션 생성 함수의 결과는 다음과 같다. 


<리듀서>


- 상태에 변화를 일으키는 함수이며, 파라미터를 두 개 받는다. 


1. 첫 번째는, 현재 상태

2. 두 번째는, 액션 객체


함수 내부에서는 switch문을 활용해서 action.type에 따라 새로운 상태를 만들어서 반환해야 한다. 


리듀서가 초기에 사용할 초기 상태값부터 먼저 설정해야 리듀서를 만들 수 있다.




리덕스 스토어를 구독한다는 것은 리덕스 스토어의 상태가 변경될 때마다 특정 함수를 실행시킨다는 의미.



리덕스를 사용할 때 주의해야 할 세 가지 


1. 스토어는 단 한 개


- 스토어는 언제나 한 개

- 스토어 여러개 생성 후 상태를 관리해서는 안 된다.

- 대신, 리듀서를 여러개 만들어서 관리할 수 있다.


2. state는 읽기 전용


- 리덕스의 상태(state)는 읽기 전용이다. 그러므로, 이 값을 절대로 수정해서는 안 된다.

- 수정을 하게 되면 리덕스의 구독 함수를 제대로 실행하지 않거나 컴포넌트의 리렌더링이 안 될 수 있다.

- 상태를 업데이트할때는 새 상태 객체를 만들어서 넣어주어야 한다.


3. 변화는 순수 함수로 구성


- 모든 변화는 순수 함수로 구성해야 함. 함수란 리듀서 함수를 뜻한다.

- 순수 함수에서 결과값을 출력할때는 파라미터 값에만 의존해야 하

Posted by sungho88
,

const SubClass = ({ children }) => {
return (
<div className="todos-wrapper">
{children}
</div>
);
};


export default SubClass;


원래는 함수형 컴포넌트이므로, (props)를 받아야하지만,


이렇게 비구조화 할당함으로써 가독성을 높일 수 있다.


또한, children의 경우 나중에 해당 컴포넌트 SubClass를 사용하게 될 때,


SubClass를 부르는 태그 안에 내용이 


위 children에 삽인된다. 


그럼 예제를 보자.


import React, { Component } from 'react';
import SubClass from './components/SubClass';

class App extends Component {
render() {
return (
<div className="App">
<SubClass>
여기에 적은 Text가 children에 들어간다~ <br/>
    <strong>아하하하</strong>
</SubClass>
</div>
);
}
}

export default App;

이렇게 하면, App.js에서 선언한 SubClass 구현 부분 <SubClass>와 </SubClass>안에 내용이 


SubClass.js에서 {children} 으로 대치되어 들어가게 된다.
















Posted by sungho88
,

React 개발환경 세팅을 하게되면 기본적으로 class형 컴포넌트로 이루어져 있다. (App.js) 


하지만, class형 컴포넌트보다 좀 더 간단하게 선언할 수 있다.


바로, 함수형 컴포넌트(Functional Component)를 사용하면 된다.


하지만, 조건이 있다.


1. 해당 컴포넌트에서는 state를 사용하지 않는다.

2. 해당 컴포넌트에서는 라이프사이클 API를 사용하지 않는다.


두 가지만 기억하면 된다. 함수형 컴포넌트를 사용하기 위해서는 위 2가지.

 

state와 컴포넌트 라이프사이클 메소드를 사용할 수 없다.


props를 전달받아서 뷰만 렌더링하는 역할만 하는 컴포넌트를 구현하고자 할 때 사용한다. 


[함수형 컴포넌트 생성 방법]


import React from 'react';


function Hello(props) {
return (
<div>Hello {props.name}</div>
)
}

export default Hello;


이렇게 간단하게 사용할 수 있다. 또는 더욱 간단하게,



import React from 'react';


const Hello = ({name}) => {
return (
<div>Hello {name}</div>
)
}


export default Hello;


이렇게 더 간단하게 사용할 수도 있다.


{name}의 경우 props에 들어있는 name 속성값이며 이를 받아서 사용한 것이다.


이것은 비구조화 할당 문법을 사용한 것이다.


클래스 컴포넌트와 다르게 props를 사용할 때, this를 사용하지 않는다.



Posted by sungho88
,

(설명)

JSX는 HTML이나 XML과 매우 비슷하게 생겼다.

하지만, HTML도 아니고 XML도 아니다.

자바스크립트의 확장 문법이다(공식 문법은 아니다)

나중에 babel-loader를 통해 자바스크립트로 변환된다.


(장점)

1. 가독성이 좋다  - 자바스크립트에 비해, JSX를 사용하면 보기 쉽고, 작성하기 쉽다.

2. 오류 검사가 가능하다 - babel-loader에 의해 오류를 감지할 수 있다.

3. 거부감없이, 쉽게 작성할 수 있다 - HTML과 유사하기 때문에 쉽게 작성이 가능하다.


(사용법)

1. 컴포넌트는 반드시 태그 하나로 묶기

- 컴포넌트에 여러 요소가 있으면, 반드시 하나의 태그로 감싸야 한다. 

- 그 이유는 컴포넌트 내부는 DOM 트리 구조 하나로 구성되어야 하기 때문이다.

- <Fragment>로 감싸면, 불필요한 div를 렌더링하는 것을 생략할 수 있다.

2. 자바스크립트 코드 삽입하기

- { 자바스크립트 표현식을 작성하려면 JSX 내부에서 중괄호{ } 안에 작성하면 된다.

3. if문 대신 삼항 연산자

- JSX 내부 자바스크립트 표현식에서 if문 사용 불가하므로 삼항 연산자를 사용할 것.

4. class 대신 className 사용

- class를 작성하면 경고 발생. class는 이미 존재하는 키워드이기 때문. className을 사용할 것.

5. 태그는 반드시 닫아야 한다.

- <br>, <input> 등의 태그는 HTML에서 닫지 않아도 작동했다. 

- 하지만, 리액트 JSX에서는 반드시 <br /> 또는 <br></br>과 같이 닫아야 오류가 발생하지 않는다.

6. 주석

- 주석은 { */ 주석임... */ } 으로 작성한다.

- 또는 주석 단축키(Ctrl + /)으로 주석을 하면 좀 더 편리하다.

- 흔히 알고 있는 // 나 /* */ 이 주석을 하게 되면 텍스트로 인식되어 그대로 화면에 표시된다.

7. &&을 사용한 조건부 렌더링

- 삼항 연산자를 쓰면 참일때 A화면 출력 거짓일때 B화면 출력을 했다.

- 하지만, 특정 조건을 만족하지 않을 때 아예 화면을 보여주고 싶지 않다면 어떻게 할까?

-  {condition ? '참이에요' : null} 과 같이 삼항연산자를 사용해도 되지만,

- {condition && '보여주세요'} 와 같이 작성해도 된다.

- 쉽다. 앞 condition이 참이면 뒤 '보여주세요'가 나오겠지만, 거짓이면 뒤에는 체크하지 않는다.


8. 인라인 스타일링 

-  CSS 스타일을 자바스크립트 객체 형식으로 생성하여 적용한다.

- 해당 키는 camelCase 형식을 사용한다.


위에 다음과 같이 선언.

const style {

backgroundColor : 'black',

border : 1px solid 'yellow'

...


사용시에는 다음과 같이 적용.

<div style={style}>BODY</div>


Posted by sungho88
,

http://reactfordesigners.com/

1. 리액트 배우는 3개 강좌

2. 리액트 다른 사람이 만든 코드 보기 3개

 

https://www.taniarascia.com/getting-started-with-react/

- 초보자들을 위해 정리 겁나 잘 해놓은 문서

- 당연히 영어.

- 공식 홈페이지보다 깊이 있지 않지만, 짧고 간결하게 개념을 설명해준다. 

https://reactjs.org/tutorial/tutorial.html

Tic Tac Toe 게임 만들기 공식 홈페이지 강좌


https://velopert.com/reactjs-tutorials

- 한국어로 검색하다보면 결국은 이 velopert 블로그로 가게 되있다.

- 한국어로 된 가장 잘 설명된 블로그인 것 같다.

Posted by sungho88
,

[What Is React?]


공식 홈페이지 링크 주소 : https://reactjs.org/tutorial/tutorial.html#what-is-react

React는 사용자 인터페이스(UI)를 구축하기위한 

선언적이고 효율적이며 유연한 JavaScript 라이브러리이다. 

이 도구를 사용하면 "구성 요소(Component)"라는 작고 분리된 코드 조각으로 

복잡한 UI를 작성할 수 있다. 기본 예제는 다음과 같다.


class ShoppingList extends React.Component {
render() {
return (
<div className="shopping-list">
<h1>Shopping List for {this.props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
</div>
);
}
}

위와같이 재미있는 XML과 유사한 태그를 사용할 것이다. 

컴포넌트를 사용하여 React에게 화면으로 보고 싶은 것을 알려준다.  

데이터가 변경되면 React는 효율적으로 Component를 업데이트하고 다시 렌더링한다.

여기서 ShoppingList는 React Component 클래스 또는 React Component 유형이다. 

Component는 props ("속성[properties]"의 약자)라는 매개 변수를 사용하고,

render 메서드를 통해 표시 할 뷰의 계층을 반환한다.

render 메서드는 화면에 표시 할 내용에 대한 설명을 반환한다.

React는 설명을 취해 결과를 표시한다. 

특히, render는 React 요소를 반환하는데, 이것은 렌더링 할 내용에 대한 간단한 설명이다. 

대부분의 React 개발자는 "JSX"라는 특수 구문을 사용하여 이러한 구조를보다 쉽게 ​​작성한다. 

<div /> 구문은 빌드시 React.createElement ('div')로 변환됩니다. 위의 예는 다음과 같다.


return React.createElement('div', {className: 'shopping-list'},
React.createElement('h1', /* ... h1 children ... */),
React.createElement('ul', /* ... ul children ... */)
);

createElement ()에 대한 자세한 내용은 API 참조 문서에서 확인할 수 있지만 

이 튜토리얼에서는 사용하지 않을 것이다. 대신에 JSX를 계속 사용할 것이다.

JSX는 JavaScript의 모든 기능을 제공한다. 

JSX 내부의 중괄호 안에 JavaScript 표현식도 넣을 수 있다. 

각 React 요소는 변수에 저장하거나 프로그램에서 전달할 수있는 JavaScript 객체이다.

위의 ShoppingList 구성 요소는,

 <div /> 및 <li />와 같은 HTML에서 사용되는 기본 제공 DOM 구성 요소 만 렌더링한다. 

그러나 사용자 정의 React 구성 요소도 작성하고 렌더링 할 수 있다. 

예를 들어 ShoppingItem이라는 컴포넌트를 생성하여, 이 컴포넌트를 호출하여 사용할 수 있다.

<ShoppingItem />과 같이 작성하면 된다. 이렇게 하면, 쇼핑 항목을 참조 할 수 있다. 

각 React 구성 요소는 캡슐화되어 독립적으로 작동 할 수 있다. 

이를 통해 간단한 구성 요소를 조각조각 모아 하나의 복잡한 UI를 작성할 수 있게 된다.


 









Posted by sungho88
,

render{

    const {datas} = this.props;   

 return (

        <ul>

            {

                this.props.datas.map(data => {

                    return <li key={data.id}><a href='/url/' + {data.id}>{data.title}</a></li>

                }

            }

        </ul>

    );

}



<a href='/url/' + {post.id}>


이 부분을 map 함수 실행되는 동안 고유의 값(id)으로 변경하면서 링크를 생성하고 싶다.


아무리 href속성에서 +를 쓰려해봐도 에러나고, 어떻게 값을 문자열로 변경하여 붙일 수 있을까?



href={'/url/' + data.id}


이렇게 하면 된다.


{} 한 뒤에 그 안에 문자열 + data.id로 작성하면 문자열로 변환되어 map함수로 실행하면 정상적으로 작동된다.


Posted by sungho88
,