// react 첫날
// react는 페이스북에서 2011년도 쯤에 만들어졌고
// react는 개발자들 사이에서 라이브러리다 프레임워크다 얘기가 많은데
// 공식홈페이지 에서는 라이브러리라고 말하고있다.
// 공식 홈페이지에서도 라이브러리다 라고 얘기를 하는데
// 라이브러리와 프레임워크의 차이는: 폴더의 구조가없음
// 프레임워크 : 폴더구조가 있음
// 패키지를 설치 할수있기때문에
// 리액트 개발을 할때 편하게 초기세팅을 설치받아서 사용할수있다.
// 메타에서 개발한것은 react,react-router 라이브러리
// 메타에서 개발하고 오픈소스에 기여중임
// 리액트를 프레임워크라고 하는 이유?
// 메타에서 라이브러리를 개발하고 npx create-react-app [폴더명]
// react를 개발할때 권장 개발환경을 구성해준다.
// react프로젝를 설정
// 그래서 블로그나 개발자들 사이에서 프레임워크라고 하는것.
// 리액트는 화면을 꾸밈을 구성할때 자바스크립트를 활요해서 html을 조작해줌 dom
// 효율적인 브라우저 렌더링을 위해
// 페이지를 효율적으로 업데이트 하기위해서
// react는 가상 DOm을 사용해서 변경된 부분마 다시 그림. (업데이트)
// 일반적인 html은 변경된 부분만 업데이트 하지않고 전체 페이지를 다시 그려주는데
// react는 가상 Dom은 메모리에 남아있고 실제 페이지의 DOM은 분리되어있는 상태
// react의 상태가 변하면 가상 DOm이 생성되고 이전 상태의 가상 DOM과 비교해서
// 업데이트 해야할 부분을 찾고 (틀린그림 찾기) 실제 DOM의 업데이트 를해준다.
// 그래서 효율적인 업데이트가 가능하다.
// 실제와 가상이 존재하고 가상과 실제가 다르다면 실제를 업데이트한다.
// 페이지 전체를 렌더링하는것은 비효율적이기떄문에 DOM내에 영역들이 나뉘어져있다.
// 나뉘어진 영역에서 변하지않은 영역은 그대로 두고 바뀐 영역만 그려준다.
// 따라서 최소한의 렌더링을 가능하게한다.
// react를 사용하는 이유
// react의 부분 렌더링
// react는 view중심 보여주는것에 집중된 라이브러리
// php ejs 이런 ssr 서버사이드렌더링
// 서버에서 페이지를 완서잇켜서 브라우저에 응답해주는것 .
// 클라이언트에서 페이지를 구성하는것을 하고싶다.
// 렌더링을 클라이언트 측에서 하고싶었던것.
// CSR
// react vue 같은것
// react는 DOM의 조작을 쉽게하기위해서 사용
// SPA을 만들기위해서 사용한다.
// react는 url을 받으면 새로운 창을만들며 넘어가는것이아니라
// 하나의 페이지에서 내용물을 계속 바궈서 페이지가 전환된것처럼 보여준다.
// react를 만든 사람은 자바스크립트를 잘하는 사람들이 만든건 아니고
// 개발을 잘하는 사람들이 모여서 만든것.
// class 문법으로 되어있음. 진입장벽이 조금있음
// DOM을 제어하던것. ??
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root"></div>
</body>
<script>
// react의 UI 기본 단위 컴포넌트
// div다 비슷한 느낌
// 컴포넌트는 자주 사용할것은 ul요소의 기본단위 (재사용성)
// 컴포넌트는 상태와 속성을 가지고있어요
// react 단방향성 데이터의 흐름
// 부모에서 자식으로 값을 전달해줄수있다.
// 데이터는 위에서 아래로 흐른다. 단방향 이걸 props라고하는데..
// 그러면 동일선상에있는 정보는 어떻게하는가? depth가 같은 경우를 말한다. 혹은 다른 노드일경우에는??
// 이러한 단점을 극복하기위해서 전역저장소를 사용한다. ex redux 라고한다. 메모리 상에 저장하게된다.
// class 로 구현해볼수있따. 컴포넌트를
// Component 모양을 만들거고 상속받아서 사용할거임
class Component {
target;
state; // 상태값 컴포넌트의 유지되는 데이터
constructor(target){
// 컴포넌트의 targer을 설정
this.target=target;
this.setup();
this.render();
console.log("나는 최초의 Render 됐지")
}
setup(){
// 컴포넌트를 초기 설정 렌더링 하기전에 동작하는 함수.
console.log("컴포넌트 초기세팅");
}
template(){
// 컴포넌트 html 템플릿을 반환 해줄거임
return "";
}
render(){
// 컴포넌트를 타겟요소에 렌더링
this.target.innerHTML= this.template();
this.setEvent();
}
setEvent(){
// 컴포넌트 이벤트 세팅
console.log("컴포넌트 이벤트 세팅");
}
setState(_state){
// 컴포넌트의 상태를 업데이트
// 업데이트 되면 리렌더링
this.state = {...this.state,..._state};
this.render();
console.log("나 상태바귐");
}
}
// 가상 DOM클래스 정의
// 렌더링 시킬거임
class VirtualDOM{
constructor(component,target){
// 매개변수로 전달받은 컴포넌트 생성후 타겟 요소전달.
// 컴포넌트 클래스 생성자 함수의 매개변수로 타겟 전달.
this.Component=new component(target);
}
render(){
this.Component.template();
}
}
// app class 를 컴포넌트 상속받아서 정의
class App extends Component {
setup(){
// App 컴포넌트 초기 세팅함수
this.state={items :["아이템 1","아이템 2"]};
}
template(){
//App 컴포넌트를 HTML을 생성해서 반환
const { items }=this.state;
return `
<ul>
${items.map((item)=>`<li>${item}</li>`)}
</ul>
<button>추가</button>
`;
}
setEvent(){
// app 컴포넌트의 이벤(트 등록
this.target.querySelector("button").addEventListener("click",()=>{
const {items} = this.state;
this.setState({items:[...items,`아이템 ${items.length+1}`]});
})
}
}
// root 선택자로 잡고
const root = new VirtualDOM(App,document.querySelector("#root"));
root.render();
</script>
</html>
class LoginBtn extends React.Component{
constructor(props){
// 부모 생성자 함수 호출
super(props);
// 컴포넌트의 상태
this.state={
isLogin : false,
}
}
// <></> jsx 문법
render(){
return(
// {} 중괄호는 EJS <% %>자바스크립트 구문을 사용하겠다는 의미
<button onClick={()=>{
// 현재 상태의 반대값으로 준것. !this.state.isLogin
this.setState({isLogin:!this.state.isLogin});
}}>
{this.state.isLogin ? "Logout" : "Login"}
</button>
)
}
}
// 루트요소를 가상 DOM으로 생성
// createRoot 메서드 렌더링을 위한 루트 객체를 생성
// 루트를 root아이디를 가진 태그로 설정
const root = ReactDOM.createRoot(document.querySelector("#root"));
// JSX문으로 LoginBtn 컴포넌트를 root에 렌더링한다.
// 태그처럼 사용하지만 리액트의 컴포넌트인다.
root.render(<LoginBtn id="2">안뇽</LoginBtn>)
class Clock extends React.Component {
constructor(props){
super(props);
this.state={
Time: new Date().toLocaleTimeString()
}
}
// 최초의 해야할 동작이있다면 didmount 에서해라 그이후의 것은 didupdate에서 해라
componentDidMount(){
// 여기 내용이 컴포넌트가 생성되면 호출됨 딱 최초에 한번
setInterval(() => {
this.setState({Time:new Date().toLocaleTimeString()});
}, 1000);
console.log("최초에 한번 실행되었다.")
}
componentDidUpdate(){
console.log("스테이트 업데이트 됨~");
}
render(){
return(
<>
<h1>아뇽 내 컴퓨터 시간</h1>
<h2>time : {this.state.Time}</h2>
</>
)
}
// react 생명주기
// 생명주기
// 화면이 그려지는 시기와 state 값이 변했을때 동작해야하는 작업이 있을경우
// 이런부분을 제어할수있게 리액트에서 만들어준 lifectcle 함수가있다. 리액트의 삶이다.
}
const root = ReactDOM.createRoot(document.querySelector("#root"));
root.render(<Clock />);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="root"></div>
</body>
<script>
const root = document.querySelector('#root');
// DOm을 직접 다루지않고 state(상태값으로 렌더링)
let state = {
items:["아이템 1","아이템 2"]
}
// 렌더링해줄함수
const render=() =>{
// 상태값이 아닌 변수를 그냥 사용하면
// 변수를 다시선언해서 초기화한다.
// 그러면 보관해야하는 값은 상태값으로 보관을 해야한다.
//
const temp=0;
const {items} =state;
root.innerHTML=`
<ul>
${items.map((item)=>`<li>${item}</li>`)}
</ul>
<button id ="append">추가</button> `
document.querySelector("#append").addEventListener("click",()=>{
// state 상태를 변경시키자.
// react는 상태값을 주시하고있는데 상태를하고있는 이유는 상태가 변하면 다시 리렌더링시킨다.
// setState으로만 변경을 하자고 약속함
setState({items:[...items,`아이템 ${items.length +1}`]})
console.log(temp);
temp++;
})
}
const setState = (_state)=>{
// 초기상태값에 추가로 새로운 상태값
state={...state,..._state};
// 상태값이 벼경되면 랜더링
render();
}
render();
</script>
</html>
// 리액트 컴포넌트에는 상태와 속서이있다.
class TEXT extends React.Component{
constructor(props){
super(props);
console.log(props);
}
render(){
return <h2>{
this.props.text
}</h2>
}
}
class LoginBtnText extends React.Component{
constructor(props){
super(props);
console.log(props);
}
render(){
console.log(this.props.flag);
// TEXT의 속성값이 props로 전달된다.
// this.props.flag 조건부 렌더링
// 속성이름으로 props에 전달하는 객체의 키값으로 전달된다.
// props = {text: "로그아웃"}
return this.props.flag ? <TEXT text="로그아웃"></TEXT> : <TEXT text="로그인"></TEXT>
}
}
class LoginBtn extends React.Component{
constructor(props)
{
super(props);
this.state ={
isLogin : false
}
console.log(props);
// bind 메서드로 바인딩하면 함수 호출할때 컨텍스트를 유지할수있다.
// 리액트에서 유용하게 쓸수있다 그러면 constructor에 접근하는지 궁금?
this.handleClick = this.handleClick.bind(this);
}
handleClick(){
console.log("눌림");
this.setState({isLogin : ! this.state.isLogin})
console.log("this.state",this.state);
}
render(){
return (<button onClick={this.handleClick
}>
<LoginBtnText flag={this.state.isLogin}/>
</button>)
}
}
class App extends React.Component{
constructor(props)
{
super(props)
this.state={
isLogin:false
}
}
render(){
return(<>
<TEXT text="로그인 레이아웃"></TEXT>
<LoginBtn/>
</>)
}
}
// 루트요소 생성
const root = ReactDOM.createRoot(document.querySelector("#root"));
root.render(<App/>);
// Component to be commented on
class CommentItem extends React.Component {
constructor(props) {
super(props)
}
render() {
return (
//In ReactDom, the attribute class used in html is changed to className.
<ul className="">
<li>{this.props.userid}</li>
<li>{this.props.content}</li>
<li>{this.props.date}</li>
</ul>
)
}
}
class CommentForm extends React.Component {
constructor(props) {
super(props)
this.state = {
// I will put the input value as the status value in the value input to send to the form
value: ""
}
this.changeHandler = this.changeHandler.bind(this)
this.submitHandler = this.submitHandler.bind(this)
}
// function to process the input
changeHandler(e) {
// destructuring and assigning the value of the input
const { value } = e.target;
this.setState({
...this.state,
value
})
}
// Function to process input if input is given
submitHandler(e) {
// block refresh event
e.preventDefault();
// Where to add comments
this.props.create(this.state.value);
// Where to initialize the state value again
this.setState({ value: "" });
}
render() {
return (
<li>
<form onSubmit={this.submitHandler}>
<h4>Comment <span> : {this.props.length}</span></h4>
<span>
<input type="text" onChange={this.changeHandler} value={this.state.value} />
</span>
<input type="submit" value="register" />
</form>
</li>
)
}
}
// Component to draw the tag lists
class CommentList extends React.Component {
constructor(props) {
super(props)
}
loop(value, index) {
// key improves performance when React identifies the element
return <CommentItem key={index} userid={value.userid} content={value.content} date={value.date} />
}
render() {
return <li>{this.props.items.map(this.loop)}</li>
}
}
// Component responsible for comment function
class Comment extends React.Component {
constructor(props) {
super(props)
this.state = {
comment: [
// add new post
{
userid: "huyn",
content: "Hello Comment #1",
date: "2023/06/29"
},
{
userid: "huyn",
content: "Hello comment number 2",
date: "2023/06/29"
}
]
}
this.create = this.create.bind(this);
}
create(content) {
// use bind to keep the context
this.setState({ comment: [{ userid: "hyun", content: content, date: "2023/06/29" }, ...this.state.comment] })
}
render() {
return (
<ul>
{/*Comment form */}
<CommentForm create={this.create} length={this.state.comment.length} />
{/* Where to show the list of comments */}
<CommentList items={this.state.comment} />
</ul>
)
}
}
// page component
class App extends React.Component {
render() {
return (
<div>
{/* Get the comment layout component */}
<Comment />
</div>
)
}
}
const root = ReactDOM.createRoot(document.querySelector('#root'));
root.render(<App />)
function getRandomNumber() {
return Math.floor(Math.random() * 100) + 1;
}
class Drawing extends React.Component {
render() {
return (
<h2>{this.props.number}</h2>
);
}
}
class Shownum extends React.Component {
render() {
const { numbers } = this.props;
return (
<div>
{numbers.map((num, index) => (
<Drawing key={index} number={num} />
))}
</div>
);
}
}
class GetNewRandNum extends React.Component {
constructor(props) {
super(props);
this.state = {
numbers: []
};
}
handleClick = () => {
const newNumber = getRandomNumber();
this.setState((prevState) => ({
numbers: [...prevState.numbers, newNumber]
}));
};
render() {
return (
<div>
<button onClick={this.handleClick}>Generate Random Number</button>
<Shownum numbers={this.state.numbers} />
</div>
);
}
}
class App extends React.Component {
render() {
return (
<GetNewRandNum />
);
}
}
const root = ReactDOM.createRoot(document.querySelector("#root"));
root.render(<App />);