코딩/위코드 코딩학습

[위코드] TIL(Today I am learned) -18(onMouse이벤트/computed property named)

카슈밀 2020. 7. 28. 19:30
반응형

어제부터 고민하던 내용인 className 동시 적용여부였다.

html에서 class를 단순히 뛰어쓰기만 하여 두가지를 동시 적용하는 것을 사용했지만, 까먹고 있었던 것이다.

그렇기에 나는 class를 한개는 동적으로 다른 한개는 정적으로 유지해야하니 더욱 더 고민했었다.

멘토님한테도 이 문제를 3번이나 물어봤지만, 나의 사항에는 적용할 수 없었다.
이때 문제 점으로 문제는 3항 연산자에도 해당 내용이 적용되는가였다.

 

why?

한개로 class를 통일하면 서로 적용해야할 class내용이 달라서였고,
2개로 넣자니 3항연산자가 들어가는 부분에 방해가 되는 것이다.

 

결국 내가 원하는 답을 알려주신 멘토님이 있었다.

단순히 뛰어쓰기해서 적용해보라고 말씀하셨다.

해당 결과물이다. 

단순히 보면 간단한 내용이지만, 해당 내용을 알지못해서 낭비한 시간이 어마어마하다.

<div onMouseOver={this.hoverOverChange} onMouseOut={this.hoverOutChange} className={this.state.display ? 
`hoverState subcategoryProducts `: `nonehoverState subcategoryProducts`}>

이거 해결하느라 5시간정도 고민 하던 도중 뛰어쓰기를 사용하여 겨우 해결. 쾌감이 엄청났다.

 

그 다음으로 발생한 문제점은 무엇인가?

바로 이벤트 문제였다.

처음에는 단순히 hover로 해당 내용을 컨트롤하려고 scss에서 배경 className에 :hover를 적용하였고,

해당 적용을 통해서 배경에는 간단히 배경색이 변하는 hover를 적용하였다.

Aesop 공식 화면 : hover 적용전 화면

 

Aesop 공식 화면 :  hover중인 모습.

그러나, 새로운 문제점은 버튼이 동시에 나오지 않는 것이었다.

이 문제의 답을 보면 매우 간단한 문제이지만, 설정하는 값은 어려웠다.

이 문제도 꽤나 시간이 걸렸다.

why? 초기state값을 설정하는 것의 중간값을 몰랐기에 나는 false를 default로 당연히 설정하였고

이것이 왜 문제였느냐? 

onMouseOver나 onMouseOut과 같은 이벤트에서 상태값에 영향을 끼치는 부분이었다.

class Mapgoods extends Component {
    constructor() {
        super();
        this.state = {
            products : [],
            btnChange: true,
            display: false
        }
    }
 }

기존의 코드 state값. onMouseOut과 충돌하는 문제를 발생하고 있었다.

class Mapgoods extends Component {
    constructor() {
        super();
        this.state = {
            products : [],
            btnChange: true,
            display: null,
        }
    }

해결한 상태의 값.

왜냐하면

onMouseOver = true

onMouseOut = false

상태였는데, state의 값인 false를 default로 잡다보니 기존값과 false를 구분하지 못하는 것이었다.

(29일에 알게된 점. 위 경우 한개의 컴포넌트에서 사용하다보니 null줘야했지만,

아래에 여러가지 컴포넌트 선택 문제로 결국 여러개로 분리해버렸다.
그랬더니 null을 줄 필요없이 그냥 false로도 작동.)

 

처음에는 3항 연산자라서 true, false만 적용하는 것인줄 알았는데, 이번 기능을 구현하면서 null이라는 상태값을 알았다.

즉, []. {} 과 같은 빈배열, 빈 스트링이 있듯이 상태에도 중간값인 undefined와 같은 null이 있다는 것을 배웠다.

 

나의 코드로 구동중인 onMouse 이벤트 적용 전 모습

null을 통해서 기존에 작동하지 않은 상황에는 해당 값이 찍히지 않는 모습이다.

기존 false로 했으면 반드시 false가 인식되었을 것이다.

 

나의 코드로 구동중인  onMouse 이벤트 적용중 모습.

해당되는 이벤트를 적용하여 해당 console값이 들어오는 모습이 출력된다.  ㄴㅇㅁㅇㄱ 쾌감~크으~

 

그런데, 새로운 문제점.....

map으로 해당값이 적용되다보니 위 모습처럼 한개만 onMouse임에도 다른 것들도 선택되고 있다.

해당하는 문제를 해결하기위해서 activeTab을 적용해볼 생각이다.

 

해당 내용은 오늘 공부한 세션과 이전에 배운 내용을 추가할 생각이다.

 

해당 작성한 내용의 코드

import React, { Component } from "react";
import { Link } from 'react-router-dom';
import "./Mapgoods.scss";


class Mapgoods extends Component {
    constructor() {
        super();
        this.state = {
            products : [],
            btnChange: true,
            display: null,
        }
    }

    componentDidMount() {
        fetch("http://localhost:3000/data/mocup.json")
            .then(res => res.json())
            .then(res => {
                this.setState({products : res.products})
            })
    }

    hadleChangeBtn = (e) => {
        this.setState ({
            btnChange : false
        });
    }

    hoverOverChange = (e) => {
        console.log("오버")
        this.setState({
            display: true    
        });    
    }

    hoverOutChange = (e) => {
        console.log("아웃")
            this.setState({
                display : false
        })
    }


    render() {
        return (
            <>
            {this.state.products.map(el => (
                <div onMouseOver={this.hoverOverChange} onMouseOut={this.hoverOutChange} className={this.state.display ?
                    `hoverState subcategoryProducts `: `nonehoverState subcategoryProducts`}>
                    <div className="subcatProductWrapper">
                        <div className="pictureImgLinkControl">
                            <Link className="pictureImgLinkTag" to="">
                                <div className="productPicture">
                                    <img className="pictureImg" src={el.image} alt=""></img>
                                </div>
                            </Link>
                        </div>
                        <div className="productSizePrice">
                            <Link to="" >
                                <h5 className="productSizePriceName">{el.name}</h5>
                                <div className="productSizePriceInfo">
                                    <span>{el.size}</span>
                                    <span className="spanSlash">/</span>
                                    <span>{el.price}</span>
                                </div>
                            </Link>
                        </div>
                        <div className="productDetailLink">
                            {/* <Link  to=""> */}
                                <div className="productDetails">
                                    <ul className="productList">
                                        <li className="productDetailsListItem">
                                            <div className="productDetailsTitle">{el.detail}</div>
                                            <div className="productDetailsContent">{el.type}</div>
                                        </li>
                                        <li className="productDetailsListItem">
                                            <div className="productDetailsTitle">{el.feeltitle}</div>
                                            <div className="productDetailsContent">{el.feel}</div>
                                        </li>
                                    </ul>
                                </div>
                                <div className={this.state.display? 
                                    `hoverState productWrapper` : `nonehoverState productWrapper`} >
                                    <button className="productCartBtn" type="button">
                                        <div className="btnContent">
                                            <span onClick={this.hadleChangeBtn} className={this.state.btnChange ? "btnLabel" : "noneBtnLabel"}>카트에 추가 — {el.price}</span>
                                            <span className={this.state.btnChange ? "btnLabelAction" : "nonebtnLabelAction" }>카트에 추가됨</span>
                                            <span className="loadingIndicatorLight"></span>
                                        </div>
                                    </button>
                                </div>
                            {/* </Link> */}
                        </div>
                    </div>
                </div>
            ))}
        </>
        )}
    }


export default Mapgoods;

 

 

 

이전에 언급했던 computed property named(이벤트 합치기)를 signup 컴포넌트에 적용하기 위해

이전 초기값을 올려보았다. 

 

import React, { Component } from "react";
import "./Signup.scss";

class Signup extends Component {
    constructor(props) {
        super(props);
        this.state = {
            email : "",
            pw: "",
            pwconfirm: "",
            firstname : "",
            lastname : "",
            pwError: false
        };
    }

    inputHandler = (e) => {
        this.setState = ({
            [e.target.name]:e.target.value
        });
    } 

    hadleValueEmail = (e) => {
        this.setState ({
            email : e.target.value
        })
    }

    hadleValuePW = (e) => {
        this.setState ({
            pw : e.target.value
        })
    }

    hadleValuepwConFirm = (e) => {
        this.setState ({
            pwconfirm : e.target.value
        })

        if (e.target.value.length > 0) {
            if (e.target.value === this.state.pw) {
                this.setState({ pwError: false });
            } else {
                this.setState({ pwError: true });
            }
        }
    }

    hadleValueFirstName = (e) => {
        this.setState ({
            firstname : e.target.value
        })
    }

    hadleValueLastName = (e) => {
        this.setState ({
            lastname : e.target.value
        })
    }

    handleSingUP = (e) => {
        // e.preventDefault();
        console.log(this.state.email,this.state.pw,this.state.firstname, this.state.lastname);
        fetch("http://10.58.5.36:8000/user/sign-up", {
                method: 'POST',
                body: JSON.stringify({
                    email: this.state.email,
                    password: this.state.pw,
                    first_name: this.state.firstname,
                    last_name: this.state.lastname
                })
            })
            .then(res => res.json())
            .then(res => {
                console.log(res)
                if (res.token) {
                    localStorage.setItem("aesop", res.token)
                    alert("회원가입을 환영합니다.")
                    this.props.history.push("/Main")
                } else { 
                    alert("이메일과 비밀번호를 확인해주세요.")
                }
            })
    }

    handleHaveAccount = (e) => {
       this.props.history.push("/Login");
    }


    render() {
        return(
            <div className="Signup">
                <form className="loginForm">
                    <div className="modalheadingWrap">
                        <h2 className="modalTitle">
                            처음 만나 뵙게 되네요. 이솝에 오신 것을 환영합니다.
                        </h2>
                        <div className="modalSubTitle">
                            계정을 만들려면 아래에 세부 정보를 입력하십시오.
                        </div>
                    </div>
                    <div className="formRow">
                        <div className="formText">
                            <label>
                                <input onChange={this.hadleValueEmail} className="formTextInput" name="email" placeholder="이메일 주소" type="email" />
                                {/* <span className="FormTextlabel">이메일 주소</span> */}
                            </label>
                        </div>
                    </div>
                    <div>
                        <div className="formRow">
                            <div className="formText">
                                <label>
                                    <input onChange={this.hadleValuePW} className="formTextInput" name="password" placeholder="패스워드" type="password" />
                                    {/* <span className="FormText-label">패스워드</span> */}
                                </label>
                            </div>
                        </div>
                        <div className="formRow">
                            <div className="formText">
                                <label>
                                    <input onChange={this.hadleValuepwConFirm} className="formTextInput" name="passwordConfirm" placeholder="패스워드 확인" type="password" />
                                    <div className={this.state.pwError ? "errorMessage" : "noneErrorTextMessage"}>
                                        이전에 사용했던 패스워드를 입력하세요.
                                    </div>
                                    {/* <span className="FormText-label">패스워드 확인</span> */}
                                </label>
                            </div>
                        </div>
                        <div className="formRowbox">
                            <div className="formTextLoginName">
                                    <label>
                                        <input onChange={this.hadleValueFirstName} className="formTextInput" maxLength="100" name="firstName" placeholder="성" type="text" />
                                        {/* <span className="FormText-label">성</span> */}
                                    </label>                   
                            </div>
                            <div className="formTextLoginName">
                                    <label>
                                        <input onChange={this.hadleValueLastName} className="formTextInput" maxLength="100" name="LastName" placeholder="이름" type="text" />
                                        {/* <span className="FormText-label">이름</span> */}
                                    </label>
                            </div>
                        </div>
                    </div>
                    <button onClick={this.handleSingUP} className={this.state.email.length > 5 && this.state.pw === this.state.pwconfirm && this.state.firstname.length >= 1 && this.state.lastname.length >= 1 ? "btnSingUPActive":"btnSignUPunActive"} type="submit">
                        <div className="btnContent">
                            <span className="btnLabel">등록</span>
                        </div>
                    </button>
                    <div className="loginHaveAccount">
                        <button onClick={this.handleHaveAccount} className="loginHaveAccountBTN">
                            이솝 계정을 가지고 계십니까?
                        </button>
                    </div>
                </form>
            </div>
        )
    }
}

export default Signup;

 

해당 sign up의 코드들이다. 매우 지저분하다.

그렇기에 중복되는 해당코드를 수정하려고 한다. 즉 이벤트 e.target.value 값들을 수정하려고 한다.

이러한 것을 적용하기 위해서

객체를 설정해야하는데, 이미 input태그에 name들을 정해주었다.

그렇기에 해당 키와 값을 불러오면 되므로

inputHandler = (e) => {

   this.setState({

     [e.target.name] : e.target.value

    });

}

로 정해주었다.

이를 Computed Property named라고 한다.

import React, { Component } from "react";
import "./Signup.scss";

class Signup extends Component {
    constructor(props) {
        super(props);
        this.state = {
            email : "",
            pw: "",
            pwconfirm: "",
            firstname : "",
            lastname : "",
            pwError: false
        };
    }

    handleSingUP = (e) => {
        // e.preventDefault();
        console.log(this.state.email,this.state.pw,this.state.firstname, this.state.lastname);
        fetch("http://10.58.5.36:8000/user/sign-up", {
                method: 'POST',
                body: JSON.stringify({
                    email: this.state.email,
                    password: this.state.pw,
                    first_name: this.state.firstname,
                    last_name: this.state.lastname
                })
            })
            .then(res => res.json())
            .then(res => {
                console.log(res)
                if (res.token) {
                    localStorage.setItem("aesop", res.token)
                    alert("회원가입을 환영합니다.")
                    this.props.history.push("/Main")
                } else { 
                    alert("이메일과 비밀번호를 확인해주세요.")
                }
            })
    }

    handleHaveAccount = (e) => {
       this.props.history.push("/Login");
    }

    inputHandler = (e) => {
        this.setState = ({
            [e.target.name]:e.target.value
        });
    } 

    hadleValuepwConFirm = (e) => {
        this.setState ({
            pwconfirm : e.target.value
        })

        if (e.target.value.length > 0) {
            if (e.target.value === this.state.pw) {
                this.setState({ pwError: false });
            } else {
                this.setState({ pwError: true });
            }
        }
    }


    render() {
        return(
            <div className="Signup">
                <form className="loginForm">
                    <div className="modalheadingWrap">
                        <h2 className="modalTitle">
                            처음 만나 뵙게 되네요. 이솝에 오신 것을 환영합니다.
                        </h2>
                        <div className="modalSubTitle">
                            계정을 만들려면 아래에 세부 정보를 입력하십시오.
                        </div>
                    </div>
                    <div className="formRow">
                        <div className="formText">
                            <label>
                                <input onChange={this.inputHandler} className="formTextInput" name="email" placeholder="이메일 주소" type="email" />
                                {/* <span className="FormTextlabel">이메일 주소</span> */}
                            </label>
                        </div>
                    </div>
                    <div>
                        <div className="formRow">
                            <div className="formText">
                                <label>
                                    <input onChange={this.inputHandler} className="formTextInput" name="password" placeholder="패스워드" type="password" />
                                    {/* <span className="FormText-label">패스워드</span> */}
                                </label>
                            </div>
                        </div>
                        <div className="formRow">
                            <div className="formText">
                                <label>
                                    <input onChange={this.inputHandler} className="formTextInput" name="passwordConfirm" placeholder="패스워드 확인" type="password" />
                                    <div className={this.state.pwError ? "errorMessage" : "noneErrorTextMessage"}>
                                        이전에 사용했던 패스워드를 입력하세요.
                                    </div>
                                    {/* <span className="FormText-label">패스워드 확인</span> */}
                                </label>
                            </div>
                        </div>
                        <div className="formRowbox">
                            <div className="formTextLoginName">
                                    <label>
                                        <input onChange={this.inputHandler} className="formTextInput" maxLength="100" name="firstName" placeholder="성" type="text" />
                                        {/* <span className="FormText-label">성</span> */}
                                    </label>                   
                            </div>
                            <div className="formTextLoginName">
                                    <label>
                                        <input onChange={this.inputHandler} className="formTextInput" maxLength="100" name="LastName" placeholder="이름" type="text" />
                                        {/* <span className="FormText-label">이름</span> */}
                                    </label>
                            </div>
                        </div>
                    </div>
                    <button onClick={this.handleSingUP} className={this.state.email.length > 5 && this.state.pw === this.state.pwconfirm && this.state.firstname.length >= 1 && this.state.lastname.length >= 1 ? "btnSingUPActive":"btnSignUPunActive"} type="submit">
                        <div className="btnContent">
                            <span className="btnLabel">등록</span>
                        </div>
                    </button>
                    <div className="loginHaveAccount">
                        <button onClick={this.handleHaveAccount} className="loginHaveAccountBTN">
                            이솝 계정을 가지고 계십니까?
                        </button>
                    </div>
                </form>
            </div>
        )
    }
}

export default Signup;

 

 

Login의 현상태 코드이다.

value값을 받는 동일한 이벤트들을 합치기 위한 이전 before코드이다.

 

import React, { Component } from "react";
import "./Login.scss";

class Login extends Component {
    constructor(props) {
        super(props);
        this.state = {
            email: "",
            password: "",
            btnChange: false
        };
    }

    inputHandler =(e)=> {
        this.setState({
            [e.target.name]:e.target.value
        },()=>console.log(this.state));

    //     if (this.state.email.length > 5 && this.state.password.length > 5) {
    //         this.setState({
    //             btnChange: true
    //         });
    //     } else {
    //         this.setState({
    //             btnChange : false
    //         })
    //     }
     };
    componentDidUpdate(_prevProps,prevState){
        if(prevState.email !== this.state.email || prevState.password !== this.state.password){
            console.log("pass")
            if(this.state.email.length > 5 && this.state.password.length > 5){
              this.setState({btnChange:true})
            }
            else{
                this.setState({btnChange:false})
            }
        }
    }
    // 로그인용 버튼
    hadleBtn = (e) => {
        fetch("http://10.58.5.36:8000/user/sign-in", {
            method: 'POST',
            body: JSON.stringify({
                email: this.state.email,
                password: this.state.pw
            })})
            .then(res => res.json())
            .then(res => {
                if (res.token) { 
                    localStorage.setItem('aesopToken', res.token);
                    this.props.history.push("/main")
                    console.log(res.token)
                } 
            })
        
    }
    

    // 회원가입용
    handleSignUp = (e) => {
        this.props.history.push('/Signup');
    }

  render() {
      console.log("render :::::", this.state)
    return (
        <div className="Login">
            <div className="modalBody">
            <div className="introduceBox">
                <h2 className="loginTitle">안녕하세요.</h2>
                <div className="loginSub">유효한 이메일 주소를 입력하세요</div>
            </div>
            <div className="formText">
                <label>
                    <input onChange={this.inputHandler} className="formTextInput" name="email" placeholder="이메일 주소"  />
                    {/* <span className="FormTextLabel">이메일 주소</span> 이부분은 애니메이션이 요구됨. 해결방안이 시급. */}
                </label>
            </div>
            <div className="formText">
                <input onChange={this.inputHandler} className="formTextInput" name="password" placeholder="비밀번호" type="password" />
            </div>
            <button onClick={this.hadleBtn} type="button" className={this.state.btnChange? "activeBTN" : "unactiveBTN"}>
                <div className="btnContent">
                    로그인
                </div>
            </button>
            <button onClick={this.handleSignUp} type="button" className="signUpcolor">
                <div className="signUpBtn">
                    회원가입
                </div>
            </button>
        </div>
        </div>
    )
  }
}

export default Login;

 

처음에는 핸들러 값안에 해당하는 것들을 집어넣었지만, 특이하게도

비동기때문인지(?)  5초과하는 값을 주었지만, 실제로는 6번값이 왔어도 false상태를 유지하였다.

그렇기에 7번의 값을 주면 그제야 true.

이것을 해결하기 위해서 고민했는데, 결국은 해당부분이 왜 이러나했는데, 결국 멘토님이 투입.

처음에는 멘토님도 비동기때문에 안되서 왜 이러나? 하시더니

오늘 배운 coponentDidUpdate를 사용하시고 바로 성공!

다시 코드를 보면서 이를 해결하라고 하셨다.

해결해주셔서 감사합니다.

inputHandler =(e)=> {
        this.setState({
            [e.target.name]:e.target.value
        },()=>console.log(this.state));

		if (this.state.email.length > 5 && this.state.password.length > 5) {
            this.setState({
                btnChange: true
            });
        } else {
            this.setState({
                btnChange : false
            })
        }
     };

그런데, 나는 아직 componentDidUpdate는 이해 못했다는 것이 함정..

728x90