위와 같이 파일업로드를 하였을때 input태그에 파일이름이 출력되게끔 구현 하고 싶었다.
하지만 에러가 발생하였고 해결하기 위해 여러가지 방법을 써본 결과 방법을 찾았다.
우선 나는 react-hook-form
라이브러리를 사용하여 구현중이다.
input file 태그는 <input type='file' {...register('photoURL')}>
으로 써두고 커스텀 하기 위해 label 태그도 썻지만 아래 해결 과정에는 간단한 예시로 설명하겠다.
<div>
{watch('photoURL') ?
<input type='text' value={watch('photoURL')[0]['name'] />
: <input type='text' value=' /> }
<input type='file' {...register('photoURL')}/>
</div>
처음엔 위처럼 코드를 쓰고 실행시켜보았지만 에러가 나왔다.
property를 읽을 수 없고 정의 되지 않는다고 나왔다.
watch('photoURL')
이 true일때만 watch('photoURL')[0]['name']
라고 써둔 코드가 읽힐 줄 알았지만 watch('photoURL')
이 false일때에도 일단 읽히고 있는 것이다.
일단 watch('photoURL')에 값이 콘솔에는 어떻게 출력되는지 알아보자.
위 아래 순서대로 watch('photoURL')에 값이 없을때와 있을때이다.
watch('photoURL')의 값이 있을때 콘솔에 찍힌 FileList를 분석해보자.
파일 name, size, type 등 정보의 키값쌍으로 이루어진 객체이다.
위와 같은 객체형태로 이루어져 있어서
watch('photoURL')[0]['name']
으로 값을 불러오는 중이다.
여기서 의문이 몇가지가 있는데 0이라는 키를 가진 FileList 이지만
braketNotation
으로 [0]
이라고 써도 출력이 되었다. -> ['0']
이미 주어진 키라면 이렇게 써야하는걸로 아는데..왜그런진 모르겠다..
Warning: You provided a
valueprop to a form field without an
onChangehandler. This will render a read-only field. If the field should be mutable use
defaultValue. Otherwise, set either
onChangeor
readOnly.
-> 경고:onChange
핸들러 없이 양식 필드에value
소품을 제공했습니다. 이것은 읽기 전용 필드를 렌더링합니다. 필드가 변경 가능해야 하는 경우defaultValue
를 사용하십시오. 그렇지 않으면onChange
또는readOnly
를 설정합니다.
위의 에러는 input 속성의 value를 defaultValue로 줘서 없앴다.
Warning: A component is changing an uncontrolled input of type undefined to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.
-> 경고: 구성 요소가 정의되지 않은 유형의 제어되지 않은 입력을 제어하도록 변경하고 있습니다. 입력 요소는 제어되지 않은 상태에서 제어된 상태로(또는 그 반대로) 전환되지 않아야 합니다. 구성 요소의 수명 동안 제어되는 입력 요소를 사용할지 또는 제어되지 않는 입력 요소를 사용할지 결정하십시오.
위의 에러와 property를 읽을 수 없다는 에러는
useState()를 사용하여 파일업로드를 하지 않았을때에는 ''
빈 문자열을 value속성값으로 주고 파일업로드를 하였을 시에는 파일 이름을 로컬 상태인 useState로 저장하여 input value에 불러오는 식으로 코드를 썻더니 원하는 결과가 나왔다.
const MyProfile = () => {
const [img, setImg] = useState('');
useEffect(() => {
if(watch('photoURL')) {
setImg(watch('photoURL')[0]['name'])
}
}, [watch('photoURL')])
return (
<div>
<input
type="text"
defaultValue={watch('photoURL') ? img : ''}
/>
<input type='file' {...register('photoURL')}/>
</div>
)
}