코딩 노트

React02 - 글자수과제 / 상태변수 객체 / 리엑트 정리 본문

React

React02 - 글자수과제 / 상태변수 객체 / 리엑트 정리

newbyeol 2023. 10. 31. 10:00

한 태그로 묶는 것을 Fragment라고 부른다. (화면의 조각)

Exam04.js 생성

첫 번째 방법 

import { useState } from "react";

//function Exam04() {}
const Exam04 = ()=> {

    const [content, setContent] = useState("");
 
    return (
        <>
            <div className="container-fluid">
                <div className="row mt-2">
                    <div className="col-md-10 offset-md-1">

                        <div class="row">
                            <div class="col">
                                <h1>네 번째 예제</h1>
                                <h3>(Q)주말에 뭐하세요?</h3>    
                            </div>
                        </div>

                        <div class="row mt-2">
                            <div class="col">
                                <textarea name="content" className="form-control" rows="6"
                                    value={content} onChange={e=>setContent(e.target.value)}/>
                                    {/* onChange는 이벤트를 수동으로 발생시켜도 값이 변하지 않는다.
                                    input은 이벤트를 발생시키면 강제로 값이 변한다. 그래서 onChange 선호 */}
                                   
                            </div>
                        </div>

                        <div class="row mt-2">
                            <div class="col text-end">
                                {content.length} / 1000
                            </div>
                        </div>
         
       
                    </div>
                </div>
            </div>
        </>
    );
}

export default Exam04;

e.target = event가 발생한 당사자

Exam04.js 생성

두 번째 방법 - 바꾸는 건 하나만 바꾸고 두 개를 쓴다! (내용과 글자수를 다른 State로 잡자)

import { useEffect, useState } from "react";

//function Exam04() {}
const Exam04 = ()=> {

    const [content, setContent] = useState("");
    const [length, setLength] = useState(0);

    //state끼리 의존성이 생기는 경우가 있다.
    //- content가 변하면 length가 변해야 한다.
    //- 수동으로 하는 것이 아니라 자동으로 변하도록 설정할 수 있다.
    //- useEffect 훅 사용
    //-useEffect(함수, [감지항목])
    useEffect(()=>{
        setLength(content.length);
    }, [content]);
   
    return (
        <>
            <div className="container-fluid">
                <div className="row mt-2">
                    <div className="col-md-10 offset-md-1">

                        <div class="row">
                            <div class="col">
                                <h1>네 번째 예제</h1>
                                <h3>(Q)주말에 뭐하세요?</h3>    
                            </div>
                        </div>

                        <div class="row mt-2">
                            <div class="col">
                                <textarea name="content" className="form-control" rows="6"
                                    value={content} onChange={e=>setContent(e.target.value)}/>
                            </div>
                        </div>

                        <div class="row mt-2">
                            <div class="col text-end">
                                {length} / 1000
                            </div>
                        </div>
         
       
                    </div>
                </div>
            </div>
        </>
    );
}

export default Exam04;

글자수계산기 완료

Exam05.js 생성

import { useEffect, useState } from "react";

const Exam05 = ()=>{

    //state를 3개로 보면 = (java, dbms, boot)
    //state를 5개로 보면 = (java, dbms, boot) -> (total, avg)

    const [java, setJava] = useState(0);
    const [dbms, setDbms] = useState(0);
    const [boot, setBoot] = useState(0);;
    const [total, setTotal] = useState(0);;
    const [avg, setAvg] = useState(0);;

    //Effect는 State에만 작성 가능
    useEffect(()=>{
        setTotal(java + dbms + boot);
    }, [java, dbms, boot]);
    useEffect(()=>{
        setAvg(total/3);
    },[total]);

    return (
        <>
            <div className="container">

                <div className="row">
                    <div className="col-md-10 offset-md-1">
                        <h1>성적 계산기</h1>
                    </div>
                </div>
                <div className="row mt-1">
                    <div className="col-md-10 offset-md-1">
                        자바 <input type="number" value={java}
                            onChange={e=>setJava(parseInt(e.target.value))}></input>
                    </div>
                </div>
                <div className="row mt-1">
                    <div className="col-md-10 offset-md-1">
                        데이터베이스 <input type="number" value={dbms}
                            onChange={e=>setDbms(parseInt(e.target.value))}></input>
                    </div>
                </div>
                <div className="row mt-1">
                    <div className="col-md-10 offset-md-1">
                        스프링부트 <input type="number" value={boot}
                            onChange={e=>setBoot(parseInt(e.target.value))}></input>
                    </div>
                </div>
                <hr/>
                <div className="row">
                    <div className="col-md-10 offset-md-1">
                        총점 = {total}점 , 평균 = {avg}
                    </div>
                </div>

            </div>
        </>
    );
};

export default Exam05;

Exam06.js 생성

import { useState } from "react";

const Exam06 = () => {
    //각각의 상태를 분리하여 관리할 때
    // const [alias, setAlias] = useState("");
    // const [gender, setGender] = useState("남자");

    //상태를 하나의 객체로 관리할 때
    const [info, setInfo] = useState({
        alias : "",
        gender : "남자"
    })

    // function changeInfo(e){}
    const changeInfo = e=>{
        // console.log(e.target); //이벤트 발생 태그 확인(e.tartget은 이벤트가 발생한 대상)
        // console.log(e.target.name, e.target.value); //이름, 값 확인

        //info에서 이벤트가 발생한 태그 명에 해당하는 필드만 입력값으로 바꾸고 나머진 그대로 둬라
        //- ...info는 info의 나머지 항목을 의미(rest 연산)
        //- 객체에 [] 표시를 쓰면 필드명을 변수로 지정할 수 있다.

        setInfo({
            ...info,
            [e.target.name] : e.target.value
        });
    };


    return (
        <>
            <h1>상태 변수가 객체인 경우</h1>

            이름 <input name="alias" type="text" value={info.alias} onChange={changeInfo}/> <br/><br/>
            성별
            <select name="gender" value={info.gender} onChange={changeInfo}>
                <option>남자</option>
                <option>여자</option>
            </select>

        </>
    );
};

export default Exam06;

왜 var을 사용하지 않는가?

= var은 오류가 생길 확률이 큼

let a = 10; //가변
const b = 20; //불변

let a = 20;
console.log(a);

배열에 대한 구조할당 연산

...을 스프레드 연산자라고 부른다.

const a = [10, 20, 30];
// const b = a.concat(40);
const b = [...a, 40];

console.log(b);
const a = [10, 20, 30];
const b = [40, 50];
const c = [...a, ...b];
console.log(c);

Exam07.js 생성 객체 상태 변수 문제(회원가입)

import { useState } from "react";

const Exam07 = ()=>{

    //객체로 상태 변수를 정의
    const [member, setMember] = useState({
        memberId:"",
        memberPw:"",
        memberPwRe:""
    });

    //객체의 상태를 한 번에 변경하는 함수를 구현
    const changeMember = (e)=>{
        setMember({
            ...member,
            [e.target.name] : e.target.value
        });
    };

    return (
        <div className="container-fluid">
            <div className="row">
                <div className="col-md-10 offset-md-1">

                    {/* 점보트론 */}
                    <div className="p-4 text-light bg-dark rounded">
                        <h1>객체 상태 변수 문제</h1>
                    </div>

                    <form autoComplete="off">

                    <div className="row mt-4">
                        <div className="col">
                            <label className="form-label">아이디</label>
                            <input type="text" name="memberId" className="form-control"
                                    value={member.memberId} onChange={changeMember}/>
                        </div>
                    </div>

                    <div className="row mt-4">
                        <div className="col">
                            <label className="form-label">비밀번호</label>
                            <input type="password" name="memberPw" className="form-control"
                                    value={member.memberPw} onChange={changeMember}/>
                        </div>
                    </div>

                    <div className="row mt-4">
                        <div className="col">
                            <label className="form-label">비밀번호 확인</label>
                            <input type="password" name="memberPwRe" className="form-control"
                                    value={member.memberPwRe} onChange={changeMember}/>
                        </div>
                    </div>

                    </form>

                    <div className="row mt-4">
                        <div className="col">
                            <button type="button" className="btn btn-primary w-100">회원가입</button>
                        </div>
                    </div>

                </div>
            </div>
        </div>
    );    
};

export default Exam07;

Exam07.js 

import { useEffect, useState } from "react";

const Exam07 = ()=>{

    //객체로 상태 변수를 정의
    const [member, setMember] = useState({ //입력데이터
        memberId:"",
        memberPw:"",
        memberPwRe:""
    });
    //입력데이터가 변하면 검사결과가 자동으로 계산되도록 처리
    useEffect(()=>{
        console.log("member가 변했습니다.")

        //id검사
        const idRegex = /^[a-z][a-z0-9]{7,19}$/;
        const idMatch = idRegex.test(member.memberId);

        //pw검사
        const pwRegex = /^[A-Za-z0-9!@#$]{8,16}$/;
        const pwMatch = pwRegex.test(member.memberPw);

        //pw-re검사
        const pwReMatch = member.memberPw.length > 0
            && member.memberPw === member.memberPwRe;
       
        setResult({
            memberId : idMatch,
            memberPw : pwMatch,
            memberPwRe : pwReMatch
        });
    }, [member]); //항목을 안 적으면 처음 한 번만 실행, 항목을 적으면 항목이 변할 때마다 실행
   

    const [result, setResult] = useState ({ //검사결과
        memberId:false,
        memberPw:false,
        memberPwRe:false,
    });

    //객체의 상태를 한 번에 변경하는 함수를 구현
    const changeMember = (e)=>{
        setMember({
            ...member,
            [e.target.name] : e.target.value
        });
    };

    return (
        <div className="container-fluid">
            <div className="row">
                <div className="col-md-10 offset-md-1">

                    {/* 점보트론 */}
                    <div className="p-4 text-light bg-dark rounded">
                        <h1>객체 상태 변수 문제</h1>
                    </div>

                    <form autoComplete="off">

                    <div className="row mt-4">
                        <div className="col">
                            <label className="form-label">아이디</label>
                            <input type="text" name="memberId" className="form-control"
                                    value={member.memberId} onChange={changeMember}/>
                        </div>
                    </div>

                    <div className="row mt-4">
                        <div className="col">
                            <label className="form-label">비밀번호</label>
                            <input type="password" name="memberPw" className="form-control"
                                    value={member.memberPw} onChange={changeMember}/>
                        </div>
                    </div>

                    <div className="row mt-4">
                        <div className="col">
                            <label className="form-label">비밀번호 확인</label>
                            <input type="password" name="memberPwRe" className="form-control"
                                    value={member.memberPwRe} onChange={changeMember}/>
                        </div>
                    </div>

                    </form>

                    <div className="row mt-4">
                        <div className="col">
                            <button type="button" className="btn btn-primary w-100">회원가입</button>
                        </div>
                    </div>

                </div>
            </div>
        </div>
    );    
};

export default Exam07;

Exam07.js

import { useEffect, useState } from "react";

const Exam07 = ()=>{

    //객체로 상태 변수를 정의
    const [member, setMember] = useState({ //입력데이터
        memberId:"",
        memberPw:"",
        memberPwRe:""
    });
    //입력데이터가 변하면 검사결과가 자동으로 계산되도록 처리
    useEffect(()=>{
        console.log("member가 변했습니다.")

        //id검사
        const idRegex = /^[a-z][a-z0-9]{7,19}$/;
        const idMatch = idRegex.test(member.memberId);

        //pw검사
        const pwRegex = /^[A-Za-z0-9!@#$]{8,16}$/;
        const pwMatch = pwRegex.test(member.memberPw);

        //pw-re검사
        const pwReMatch = member.memberPw.length > 0
            && member.memberPw === member.memberPwRe;
       
        setResult({
            memberId : idMatch,
            memberPw : pwMatch,
            memberPwRe : pwReMatch
        });
    }, [member]); //항목을 안 적으면 처음 한 번만 실행, 항목을 적으면 항목이 변할 때마다 실행
   

    const [result, setResult] = useState ({ //검사결과
        memberId:false,
        memberPw:false,
        memberPwRe:false,
    });

    //객체의 상태를 한 번에 변경하는 함수를 구현
    const changeMember = (e)=>{
        setMember({
            ...member,
            [e.target.name] : e.target.value
        });
    };

    return (
        <div className="container-fluid">
            <div className="row">
                <div className="col-md-10 offset-md-1">

                    {/* 점보트론 */}
                    <div className="p-4 text-light bg-dark rounded">
                        <h1>객체 상태 변수 문제</h1>
                    </div>

                    <form autoComplete="off">

                    <div className="row mt-4">
                        <div className="col">
                            <label className="form-label">아이디</label>
                            <input type="text" name="memberId"
                                    className={`
                                        form-control
                                        ${result.memberId ? 'is-valid' : 'is-invalid'}
                                        `}
                                    value={member.memberId} onChange={changeMember}/>
                                    <div className="valid-feedback">멋진 아이디입니다!</div>
                                    <div className="invalid-feedback">사용할 수 없는 아이디입니다!</div>
                        </div>
                    </div>

                    <div className="row mt-4">
                        <div className="col">
                            <label className="form-label">비밀번호</label>
                            <input type="password" name="memberPw"
                                    value={member.memberPw} onChange={changeMember}
                                    className={`
                                        form-control
                                        ${result.memberPw ? 'is-valid' : 'is-invalid'}
                                    `}
                                    />
                            <div className="valid-feedback">올바른 형식의 비밀번호입니다.</div>
                            <div className="invalid-feedback">비밀번호 형식이 올바르지 않습니다.</div>
                        </div>
                    </div>

                    <div className="row mt-4">
                        <div className="col">
                            <label className="form-label">비밀번호 확인</label>
                            <input type="password" name="memberPwRe"
                                    value={member.memberPwRe} onChange={changeMember}
                                    className={`
                                        form-control
                                        ${result.memberPwRe ? 'is-valid' : 'is-invalid'}
                                    `}
                                    />
                            <div className="valid-feedback">비밀번호가 일치합니다.</div>
                            <div className="invalid-feedback">비밀번호가 일치하지 않습니다.</div>
                        </div>
                    </div>

                    </form>

                    <div className="row mt-4">
                        <div className="col">
                            <button type="button" className="btn btn-primary w-100"
                                disabled={!(result.memberId && result.memberPw
                                                    && result.memberPwRe)}>회원가입</button>
                        </div>
                    </div>

                </div>
            </div>
        </div>
    );    
};

export default Exam07;

Exam07.js 문제 해결 후 blur 추가

import { useEffect, useState } from "react";

const Exam07 = ()=>{

    //객체로 상태 변수를 정의
    const [member, setMember] = useState({//입력데이터
        memberId:"",
        memberPw:"",
        memberPwRe:""
    });
    const [result, setResult] = useState({//검사결과
        memberId:null,
        memberPw:null,
        memberPwRe:null
    });
    //입력데이터가 변하면 검사결과가 자동으로 계산되도록 처리
    const checkMember = ()=>{
        //console.log("member가 변했습니다");
        //ID검사
        const idRegex = /^[a-z][a-z0-9]{7,19}$/;
        const idMatch = member.memberId.length === 0 ? null : idRegex.test(member.memberId);

        //PW검사
        const pwRegex = /^[A-Za-z0-9!@#$]{8,16}$/;
        const pwMatch = member.memberPw.length === 0 ? null : pwRegex.test(member.memberPw);

        //PW-RE검사
        const pwReMatch = member.memberPwRe.length === 0 ? null :
                                        member.memberPw.length > 0 && member.memberPw === member.memberPwRe;

        setResult({
            memberId : idMatch,
            memberPw : pwMatch,
            memberPwRe : pwReMatch
        });
    };

    //useEffect(checkMember, [member]);

    //객체의 상태를 한 번에 변경하는 함수를 구현
    const changeMember = (e)=>{
        setMember({
            ...member,
            [e.target.name] : e.target.value
        });
    };

    return (
        <div className="container-fluid">
            <div className="row">
                <div className="col-md-10 offset-md-1">
                   
                    {/* 점보트론 */}
                    <div className="p-4 text-light bg-dark rounded">
                        <h1>객체 상태 변수 문제</h1>
                    </div>

                    <form autoComplete="off">

                    <div className="row mt-4">
                        <div className="col">
                            <label className="form-label">아이디</label>
                            <input type="text" name="memberId"
                                    className={`
                                        form-control
                                        ${result.memberId === true ? 'is-valid' : ''}
                                        ${result.memberId === false ? 'is-invalid' : ''}
                                    `}
                                    value={member.memberId} onChange={changeMember}
                                            onBlur={checkMember}/>
                            <div className="valid-feedback">멋진 아이디입니다!</div>
                            <div className="invalid-feedback">사용할 수 없는 아이디입니다</div>
                        </div>
                    </div>

                    <div className="row mt-4">
                        <div className="col">
                            <label className="form-label">비밀번호</label>
                            <input type="password" name="memberPw"
                                    className={`
                                        form-control
                                        ${result.memberPw === true ? 'is-valid' : ''}
                                        ${result.memberPw === false ? 'is-invalid' : ''}
                                    `}
                                    value={member.memberPw} onChange={changeMember}
                                        onBlur={checkMember}/>
                            <div className="valid-feedback">올바른 형식의 비밀번호입니다</div>
                            <div className="invalid-feedback">비밀번호 형식이 올바르지 않습니다</div>
                        </div>
                    </div>

                    <div className="row mt-4">
                        <div className="col">
                            <label className="form-label">비밀번호 확인</label>
                            <input type="password" name="memberPwRe"
                                    className={`
                                        form-control
                                        ${result.memberPwRe === true ? 'is-valid' : ''}
                                        ${result.memberPwRe === false ? 'is-invalid' : ''}
                                    `}
                                    value={member.memberPwRe} onChange={changeMember}
                                    onBlur={checkMember}/>
                            <div className="valid-feedback">비밀번호가 일치합니다</div>
                            <div className="invalid-feedback">비밀번호가 일치하지 않습니다</div>
                        </div>
                    </div>

                    </form>

                    <div className="row mt-4">
                        <div className="col">
                            <button type="button" className="btn btn-primary w-100"
                                disabled={!(result.memberId === true && result.memberPw === true
                                                    && result.memberPwRe === true)}>
                                회원가입
                            </button>
                        </div>
                    </div>

                </div>
            </div>
        </div>
    );    
};

export default Exam07;

React 배운 내용 요약

React

- SPA(Single Page Application)을 구현할 수 있는 기술이다.

- 라이브러리로 분류하지만 프레임워크의 특징을 가지고 있다.

- NodeJS를 통해 직접 실행/빌드가 가능하도록 구성되어 있다.

- Webpack 시스템을 도입하여 import/export가 가능하게 되어있다.

- create-react-app으로 생성한 프로젝트는 위 환경을 무조건 가지고있다.

- React 앱의 시작지점은 index.js

- React 앱의 빌드와 관련된 파일은 package.json

- 모든 요소들이 index.js를 향하도록 연결해놓고 빌드하면 최종결과물(production)이 나온다.

- 하나로 다 만들면 너무 복잡해지기 때문에 컴포넌트(Component)를 만들어서 화면을 분리하여 개발하도로 구성되어 있다.    - 클래스형 컴포넌트    - 함수형 컴포넌트 

- 컴포넌트에는 상태(state)가 존재한다.

    - useState 훅을 이용하여 생성

    - `const [이름, 세터함수] = useState(초기값)`

    - 초기값은 단일데이터 or 객체 or 배열 일 수 있다.

    - state를 표현식 `{}`를 사용하여 화면의 특정 영역에 출력할 수 있다.

- 컴포넌트에는 이펙트(effect)가 존재한다.

    - state 간에 서로 영향을 줄 수 있도록 설정할 수 있다.

    - `useEffect(함수, [감지항목])`

    - effect는 앱 성능에 중대한 영향을 미치므로 사용을 자제하는게 좋다.

    - 만약 감지항목이 없다면 처음에 딱 한 번만 실행한다.

'React' 카테고리의 다른 글

React06 - Rest API2(insert, delete, selectOne, update)  (0) 2023.11.03
React05 - Rest API  (0) 2023.11.02
React04 - todoList CRUD / 백엔드 연결  (0) 2023.11.02
React03 - item CRUD / 모달  (0) 2023.11.01
React01 - React 기초  (0) 2023.10.30