인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

유형주님의 프로필 이미지
유형주

작성한 질문수

파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트

리액트 프로젝트를 Azure Storage에 배포하기

AZURE 등록후 백엔드 프론트엔드 각각 잘올라왔는데 로그인을 하려고 보니 아래와 같은 에러가 발생해서 문의드립니다.

작성

·

192

0

- 여러분의 질문을 고대하고 있습니다. :-)
- 질문 전에 검색을 먼저 해보세요. 사람 사는 게 다 비슷하다는 것을 알게 됩니다.
- 예의는 거침없이 질문하기 위한 최고의 발명품입니다.
- 100개의 설명이 스크린샷 한방 보다 못할 수 있습니다.
- 코드를 첨부하면 전세계 누구나 이해할 수 있는 질문이 됩니다.
- 하나의 질문에는 하나의 주제를 담아야 답변도 예리해집니다.
- 시행착오를 알려주시면 곧 바로 원하는 문제에 집중할 수 있습니다.

- 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.
 

장고에서는 별다른 에러는 없는데 위 내용은 장고에서 username을 불러오지 못한다는 의미인걸까요..? 

답변 2

1

이진석님의 프로필 이미지
이진석
지식공유자

안녕하세요.

이는 JS 에서 undefined 으로부터 username 이름의 속성을 참조했기 때문에 TypeError가 발생했다는 오류입니다.

Login.js에서 실습을 하셨다면 Form 컴포넌트에 onFinish 속성값으로 onFinish 함수를 콜백으로 지정하셨을 텐데요. 이때 form submit이 이뤄질 때 onFinish 함수가 호출이 되고 인자로 form fields 값들이 넘어옵니다.

현재 Login.js 의 42번째 라인의 코드가 무엇인가요? 만약 const { username, password } = values; 라면, values이 각 필드값이 들어있는 object여야하는데 undefined라는 것은 현재 리액트 구현에 뭔가 문제가 있다는 것입니다.

혹시 속성값 지정 시에 onFinish={onFinish}  가 아니라 onFinish={onFinish()} 로 구현하신 것은 아닌가요?

코드를 차근차근 확인해보시며 정리해보시고나서, 다시 질문 부탁드립니다.

화이팅입니다. :-)

0

유형주님의 프로필 이미지
유형주
질문자

안녕하세요 강사님 질문올린 후에 다시한번 코드를 수정해서 테스트 해봤는데 이번엔

 

어떤 오류도 발생하지 않고 새로고침만 실행 됬습니다. 

 

export default function Login() {
    const {dispatch} = useAppContext()
    const location = useLocation();
    const history = useHistory();
    const [errors, setErrors] = useState({});
    // const [inputs, setInputs] = useState({});
    const [username, setUsername] = useState('')
    const [password, setPassword] = useState('')
    const [loading, setLoading] = useState(false);
    const [formDisabled, setFormDisabled] = useState(false)
    const {from: loginRedirectUrl} = location.state || {
        from: {pathname : "/"}
    }

    const onSubmit = () => {
        // e.preventDefault()
        setErrors({});

        const data = {username, password}

        axiosInstance.post("/accounts/token/", data)
            .then(response => {
                const {
                    data : {
                        token: jwtToken,
                    }
                } = response
                dispatch(setToken(jwtToken))
                history.push(loginRedirectUrl)
            })
            .catch(error => {
                if (error.response) {
                    setErrors({
                        username: (error.response.data.username || []).join(""),
                        password: (error.response.data.password || []).join(""),
                    });
                    console.log('데이터 수신불가')
                    console.log(error.response)
                    history.go()
                }
            })
            .finally(() => {
                setLoading(true)
            });
    };

    useEffect(() => {
        const isEnable=  Object.values(username).every(s => s.length > 0);
        setFormDisabled(!isEnable)
    }, [username])

    const onUsernameChange = (e) => {
        setUsername(e.target.value)
    }

    const onPasswordChange = (e) => {
        setPassword(e.target.value)
    }

    return (
        <div className="app">
            {/* Start Header */}
            <div className="header">
                <div className="logo">
                    <LogoBox/>
                </div>
                <div className="search-bar">
                    <SearchBox/>
                </div>
                <div className="top-nav-bar">
                    <AccountMenu />
                </div>
            </div>
            {/* End Header */}


            <div className="signup">
                <Paper
                    sx={{
                        height: '600px',
                        width: '56%',
                        marginLeft: 28,
                        alignItems: 'center'
                    }}
                    elevation={9}
                >
                    <form onSubmit={onSubmit}>
                        <Stack alignItems={'center'} margin={10} spacing={3} >
                            <TextField
                                id="outlined-username-input"
                                label="Username"
                                type="username"
                                autoComplete="current-username"
                                name="username"
                                onChange={onUsernameChange}
                                sx={{ m: 1, width: '50ch' }}
                                InputProps={{
                                    startAdornment : (
                                        <InputAdornment position="start">
                                            <AccountCircle />
                                        </InputAdornment>
                                    )
                                }}
                            />
                            {errors.username}
                            <TextField
                                id="outlined-password-input"
                                label="Password"
                                type="password"
                                autoComplete="current-password"
                                name="password"
                                onChange={onPasswordChange}
                                sx={{ m: 1, width: '50ch' }}
                                InputProps={{
                                    startAdornment : (
                                        <InputAdornment position="start">
                                            <PasswordIcon />
                                        </InputAdornment>
                                    )
                                }}
                            />
                            {errors.password}
                            <Button
                                type="submit"
                                value="로그인"
                                disabled={loading || formDisabled}
                                variant="contained"
                                fullWidth
                            >
                                Login
                            </Button>
                            <Button
                                href="/accounts/signup/"
                                value="회원가입"
                                variant="contained"
                                fullWidth
                            >
                                Sign Up
                            </Button>
                        </Stack>
                    </form>
                </Paper>
            </div>

 

로컬해서 테스트할 떄는 정상적으로 작동하는데.... 혹시 프론트는 로컬과 클라우드로 올릴때 

코드가 다르게 적용되는 부분이 있나요? 위 코드는 Material UI 프레임워크를 사용해서 테스트하여

onFinish가 아닌 onSubmit으로 구현하였습니다. 

이진석님의 프로필 이미지
이진석
지식공유자

안녕하세요.

페이지가 새로고침이 된 것이 아니라, form 기본의 submit이 동작을 한 듯 하구요. <form>에 action지정이 없으니 현재 페이지로 submit이 동작을 하여 새로고침이 된 듯한 효과가 발생한 듯 합니다.

유형주 님께서는 <form> 의 기본 submit 동작을 수행하지 않고, 직접 구현하신 로직을 onSubmit을 통해 수행하실려는 것이잖아요. 그렇다면 form onSubmit에 지정된 onSubmit 함수에서 e.preventDefault()를 호출하거나 return false;를 해주셔야 합니다.

보여주신 코드에서는 e.preventDefault(); 를 호출하셨지만 주석처리를 하셨더라구요. e 객체는 onSubmit 함수의 첫번째 인자로 지정이 됩니다. 인자에서 e 객체를 받아서 호출해주시면 적어도 말씀하신 페이지가 새로고침이 되는 듯한 증상이 없어지지 않을까 싶습니다.

조급하게 생각하지 마시고, 차근차근 정리해보며 문제를 풀어가보세요. 이 모든 것이 하나 하나 쌓여 경험이 되는 것입니다.

화이팅입니다. :-)

유형주님의 프로필 이미지
유형주

작성한 질문수

질문하기