[REACT] onChange에 event handler 함수를 넘겨야 하는데, 다른 인자를 같이 넘기려면 어떻게 하나요?
Q.
input
태그에서 onChange
를 했을 때, event handler 함수가 다 비슷하거든요. 혹시 해당 함수를 공통화시켜서 코드를 확 줄일 수 있는 방법 없을까요??
render 함수 내부 코드는 다음과 같습니다.
<input
name="picture1"
onChange={this.handleImageChange1}
className="imageUploadBtn"
required
/>
<input
name="picture2"
onChange={this.handleImageChange2}
className="imageUploadBtn"
required
/>
<input
name="picture3"
onChange={this.handleImageChange3}
className="imageUploadBtn"
required
/>
함수 정의 부분 코드는 다음과 같습니다.
handleImageChange1 = (event) => {
event.preventDefault();
let reader1 = new FileReader();
let BnBImg1 = event.target.files[0];
reader1.onloadend = () => {
this.setState({
BnBImg1: BnBImg1,
imagePreviewUrl1: reader1.result,
isThereImage1: 'block'
})
console.log('reader1.result', reader1.result);
}
reader1.readAsDataURL(BnBImg2)
}
handleImageChange2 = (event) => {
event.preventDefault();
let reader2 = new FileReader();
let BnBImg2 = event.target.files[0];
reader2.onloadend = () => {
this.setState({
BnBImg2: BnBImg2,
imagePreviewUrl2: reader2.result,
isThereImage2: 'block'
})
console.log('reader2.result', reader2.result);
}
reader2.readAsDataURL(BnBImg2)
}
handleImageChange3 = (event) => {
event.preventDefault();
let reader3 = new FileReader();
let BnBImg3 = event.target.files[0];
reader3.onloadend = () => {
console.log('나와랑', reader3);
console.log('나와랑2', BnBImg3)
this.setState({
BnBImg3: BnBImg3,
imagePreviewUrl3: reader3.result,
isThereImage3: 'block'
})
console.log('reader3.result', reader3.result);
}
reader3.readAsDataURL(BnBImg3)
}
그리고 함수를 공통화 시키려면, 왠지 지금 바뀐 요소가 1, 2, 3 중에 어떤 input 태그인지 인자같은 걸로 넘겨줘야할것 같은데…
onchange에는 함수의 정의나 함수 이름만 전달해야 되던데…? 인자를 도대체 어떻게 넘길 수 있는건가요?
A.
일단 본격적으로 질문에 대한 답을 설명하기 전에 정리하고 넘어갈 게 있습니다.
해당 함수 내에서 불러오고자 하는 FileReader
함수를 reader
로 선언하고자 하는 상황이예요.
reader2
, reader3
, reader4
이런 식으로 따로 선언할 필요가 없습니다.
왤까요????? 어차피 선언한 내용은 scope에 막히기 때문입니다.
let reader = new FileReader();
그냥 이렇게 선언하도록 하겠습니다.
같은 이유로, ★★ 해당 onChange
★★에 대한 event
를 인자로 받아서 ★★ 해당 event
★★의 event.target.files[0]
을 각 함수 내에서 사용하고자 하는 거니, BnBImg2
, BnBImg3
, BnBImg4
도 각각의 이름을 다르게 선언할 필요가 없습니다.
let BnBImg = event.target.files[0];
따라서 이렇게 바꾸도록 하죠!!
이렇게 바꾸고 나면 각 함수의 기본적인 형태는 이렇게 변합니다.
handleImageChange2 = (event) => {
event.preventDefault();
let reader = new FileReader();
let BnBImg = event.target.files[0];
reader.onloadend = () => {
this.setState({
BnBImg2: BnBImg,
imagePreviewUrl2: reader.result,
isThereImage2: 'block'
})
console.log('reader.result', reader.result);
}
reader.readAsDataURL(BnBImg)
}
이제 다른거라곤, setState
안에 들어있는 key값인 BnBImg2
, imagePrevieUrl2
, isThereImage2
뿐입니다.
게다가 뒤에 붙은 숫자만 2, 3, 4로 다른데, 변수로 관리해줄수 있지 않을까요?!!??
그런데… 변수를 어디서 받아오죠? 각 input
태그의 onChange에서 변수를 보내줘야 할텐데… 보내줄 수 있는 방법이 있을까요?????
<input
name="picture2"
onChange={this.handleImageChange2}
className="imageUploadBtn"
required
/>
여기서 말이에요…!!
네!!! 있습니다!!!
현재는 onChange
event handler가 onChange
에 걸리는 함수에 event
하나의 인자만을 첫 번째 인자로 전달해줍니다. 이게 무슨 말이냐구요???
onChange
, onClick
과 같은 경우에는 우측에 함수 실행문을 넣지 않고 정의만 넣어줬었죠??
그러면 onClick
과 onChange
가 그 함수도 자동으로 실행시켜주고, onClick
과 onChange
이벤트에서 받은 event를 해당 함수의 ★★★ 첫 번째 인자★★★로 넘겨줍니다!!!!!
<input
name="picture2"
onChange={(event) => this.handleImageChange2(event)}
className="imageUploadBtn"
required
/>
원래는 이런 형태였다는 뜻이죠!!
event
를 받아와서, this.handleImageChange2
라는 함수에 event
를 첫 번째 인자로 넘겨준다!!
그런데 제가 왜 ‘첫 번째 인자’라는 표현을 썼을까요…?
당연한 거지만… 우리가 코딩을 하고있긴 해도, 이건 기본적으로 함수기 때문에!! 두 번째 인자와 세 번째 인자에 꼭 넘겨줘야만 하는 값이 함수 자체에 정의되어 있지 않다면, 우리가 임의로 두 번째 인자, 세 번째 인자를 설정해서 넘겨줄 수 있다는 소리이기 때문입니다~~~
그렇다면… 해당 함수에서 특정 숫자(2, 3, 4)를 가져다 쓸 수 있도록 input
태그의 onChange attribute
에서 넘겨줄 수 있지 않을까요?!?!??!?!?!??
<input
name="picture2"
onChange={(event) => this.handleImageChange2(event, 2)}
className="imageUploadBtn"
required
/>
이렇게 말입니다!!!!!!!
이렇게 숫자를 넘겨줬다면, 위의 함수에서도 그걸 받아줘야겠죠??
handleImageChange2 = (event, number) => {
event.preventDefault();
let reader = new FileReader();
let BnBImg = event.target.files[0];
reader.onloadend = () => {
this.setState({
BnBImg2: BnBImg,
imagePreviewUrl2: reader.result,
isThereImage2: 'block'
})
console.log('reader.result', reader.result);
}
reader.readAsDataURL(BnBImg)
}
맨 위를 보세요!! event
외에 number
라는 것도 인자로 받아올거야~ 라는 것을 함수에 알려주었습니당.
이제 number
를 인자로 받아왔으니, 함수 내부에서 사용할 수 있게 되었어요!!!
이 number
인자를 써줘야 하는 곳은 setState 함수 안의 객체 안의 key값입니다.(;;;;;;;;;;)
객체의 key값에 변수를 넣는다…………. 변수를 그냥 쓸 수 있던가요?
아닙니다 ㅎ… 제가 이걸 엄청 많이 틀려서 예리님에게 호되게 혼났었는데요…
예리님은 이 필기 내용이 제 메모장의 어느 부분에 있는지도 알고 계시답니다…
객체의 프로퍼티명에 접근할 때 어떻게 접근하는지, 모두 알고 계시죠??
보통 .
으로 접근하지만, 대괄호를 써야만 하는 때가 있었습니다.
대괄호 안에는 변수가 들어갈 수 있어요…
자, 그러면 우리 대괄호를 써서 key를 다시 써보도록 합시다!!
handleImageChange2 = (event, number) => {
event.preventDefault();
let reader = new FileReader();
let BnBImg = event.target.files[0];
reader.onloadend = () => {
this.setState({
['BnBImg' + number]: BnBImg,
['imagePreviewUrl' + number]: reader.result,
['isThereImage' + number]: 'block'
})
console.log('reader.result', reader.result);
}
reader.readAsDataURL(BnBImg)
}
대괄호 안에서 string과, 인자로 받아온 변수를 조합해 key값을 완성했습니다!
이제 함수 이름은 하나로 통일해도 되겠죠?
handleImageChange = (event, number) => {
event.preventDefault();
let reader = new FileReader();
let BnBImg = event.target.files[0];
reader.onloadend = () => {
this.setState({
['BnBImg' + number]: BnBImg,
['imagePreviewUrl' + number]: reader.result,
['isThereImage' + number]: 'block'
})
console.log('reader.result', reader.result);
}
reader.readAsDataURL(BnBImg)
}
handleImageChange
라는 하나의 함수로 만들어주었습니다. 함수명이 바뀌었으니, onChange
에 걸려있는 함수명도 바꿔주는 걸 잊지 맙시다!!!!!!!!
<input
name="picture2"
onChange={(event) => this.handleImageChange(event, 2)}
className="imageUploadBtn"
required
/>
<input
name="picture3"
onChange={(event) => this.handleImageChange(event, 3)}
className="imageUploadBtn"
required
/>
<input
name="picture4"
onChange={(event) => this.handleImageChange(event, 4)}
className="imageUploadBtn"
required
/>