-
React, 컴포넌트, Autocomplete 기능, ClickToEdit 기능 구현Topic/React | Redux 2022. 1. 5. 21:41반응형
Autocomplete (자동완성) 구현 ✔️
테스트 케이스들을 다 통과하지 못해 아쉬웠지만 구현된걸 보니 유용하게? 쓰일 것 같다 !
import { useState, useEffect } from 'react'; import styled from 'styled-components'; const deselectedOptions = [ 'rustic', 'antique', 'vinyl', 'vintage', 'refurbished', '신품', '빈티지', '중고A급', '중고B급', '골동품' ]; /* TODO : 아래 CSS를 자유롭게 수정하세요. */ const boxShadow = '0 4px 6px rgb(32 33 36 / 28%)'; const activeBorderRadius = '1rem 1rem 0 0'; const inactiveBorderRadius = '1rem 1rem 1rem 1rem'; export const InputContainer = styled.div` margin-top: 8rem; background-color: #ffffff; display: flex; flex-direction: row; padding: 1rem; border: 1px solid rgb(223, 225, 229); border-radius: ${inactiveBorderRadius}; z-index: 3; box-shadow: 0; &:focus-within { box-shadow: ${boxShadow}; } > input { flex: 1 0 0; background-color: transparent; border: none; margin: 0; padding: 0; outline: none; font-size: 16px; } > div.delete-button { cursor: pointer; } `; export const DropDownContainer = styled.ul` background-color: #ffffff; display: block; margin-left: auto; margin-right: auto; list-style-type: none; margin-block-start: 0; margin-block-end: 0; margin-inline-start: 0px; margin-inline-end: 0px; padding-inline-start: 0px; margin-top: -1px; padding: 0.5rem 0; border: 1px solid rgb(223, 225, 229); border-radius: 0 0 1rem 1rem; box-shadow: ${boxShadow}; z-index: 3; > li { padding: 0 1rem; } `; export const Autocomplete = () => { /** * Autocomplete 컴포넌트는 아래 3가지 state가 존재합니다. 필요에 따라서 state를 더 만들 수도 있습니다. * - hasText state는 input값의 유무를 확인할 수 있습니다. * - inputValue state는 input값의 상태를 확인할 수 있습니다. * - options state는 input값을 포함하는 autocomplete 추천 항목 리스트를 확인할 수 있습니다. */ const [hasText, setHasText] = useState(false); const [inputValue, setInputValue] = useState(''); const [options, setOptions] = useState(deselectedOptions); // useEffect를 아래와 같이 활용할 수도 있습니다. useEffect(() => { if (inputValue === '') { setHasText(false); } }, [inputValue]); // TODO : input과 dropdown 상태 관리를 위한 handler가 있어야 합니다. const handleInputChange = (event) => { /** * handleInputChange 함수는 * - input값 변경 시 발생되는 change 이벤트 핸들러입니다. * - input값과 상태를 연결시킬 수 있게 controlled component로 만들 수 있고 * - autocomplete 추천 항목이 dropdown으로 시시각각 변화되어 보여질 수 있도록 상태를 변경합니다. * * handleInputChange 함수를 완성하여 아래 3가지 기능을 구현합니다. * * onChange 이벤트 발생 시 * 1. input값 상태인 inputValue가 적절하게 변경되어야 합니다. * 2. input값 유무 상태인 hasText가 적절하게 변경되어야 합니다. * 3. autocomplete 추천 항목인 options의 상태가 적절하게 변경되어야 합니다. * Tip : options의 상태에 따라 dropdown으로 보여지는 항목이 달라집니다. */ setInputValue(event.target.value) setHasText(!hasText); }; const handleDropDownClick = (clickedOption) => { /** * handleDropDownClick 함수는 * - autocomplete 추천 항목을 클릭할 때 발생되는 click 이벤트 핸들러입니다. * - dropdown에 제시된 항목을 눌렀을 때, input값이 해당 항목의 값으로 변경되는 기능을 수행합니다. * * handleInputChange 함수를 완성하여 아래 기능을 구현합니다. * * onClick 이벤트 발생 시 * 1. input값 상태인 inputValue가 적절하게 변경되어야 합니다. * 2. autocomplete 추천 항목인 options의 상태가 적절하게 변경되어야 합니다. */ setInputValue(deselectedOptions[clickedOption]); console.log(clickedOption) }; const handleDeleteButtonClick = (e) => { /** * handleDeleteButtonClick 함수는 * - input의 오른쪽에 있는 X버튼 클릭 시 발생되는 click 이벤트 핸들러입니다. * - 함수 작성을 완료하여 input값을 한 번에 삭제하는 기능을 구현합니다. * * handleDeleteButtonClick 함수를 완성하여 아래 기능을 구현합니다. * * onClick 이벤트 발생 시 * 1. input값 상태인 inputValue가 빈 문자열이 되어야 합니다. */ setInputValue(''); }; // Advanced Challenge: 상하 화살표 키 입력 시 dropdown 항목을 선택하고, Enter 키 입력 시 input값을 선택된 dropdown 항목의 값으로 변경하는 handleKeyUp 함수를 만들고, // 적절한 컴포넌트에 onKeyUp 핸들러를 할당합니다. state가 추가로 필요한지 고민하고, 필요 시 state를 추가하여 제작하세요. return ( <div className='autocomplete-wrapper'> <InputContainer onChange={handleInputChange}> {/* TODO : input 엘리먼트를 작성하고 input값(value)을 state와 연결합니다. handleInputChange 함수와 input값 변경 시 호출될 수 있게 연결합니다. */} {/* TODO : 아래 div.delete-button 버튼을 누르면 input 값이 삭제되어 dropdown이 없어지는 handler 함수를 작성합니다. */} <input type="text" onChange={handleInputChange} value={inputValue}/> <div className='delete-button' onClick={handleDeleteButtonClick}>×</div> </InputContainer> {/* TODO : input 값이 없으면 dropdown이 보이지 않아야 합니다. 조건부 렌더링을 이용해서 구현하세요. */} {inputValue?<DropDown options={options} handleComboBox={inputValue} onClick={(e)=>handleDropDownClick(e)}/>:null} </div> ); }; export const DropDown = ({ options, handleComboBox, onClick }) => { return ( <DropDownContainer> {options.map((x,i)=> x.indexOf(handleComboBox)>-1?<div onClick={()=>onClick(i)}>{x}</div>:null )} </DropDownContainer> ); };
ClickToEdit 구현 ✔️
input 창을 클릭하면 수정이 가능하고, input 창이 아닌 다른 곳을 클릭하면 수정한 내용이 반영되는 기능을 가진 컴포넌트
사용자와의 소통이 가능하게 하는 컴포넌트 구현이어서 재밌는 부분들이 많았다 !import { useEffect, useState, useRef } from 'react'; import styled from 'styled-components'; export const InputBox = styled.div` text-align: center; display: inline-block; width: 150px; height: 30px; border: 1px #bbb dashed; border-radius: 10px; margin-left: 1rem; `; export const InputEdit = styled.input` text-align: center; display: inline-block; width: 150px; height: 30px; `; export const InputView = styled.div` text-align: center; align-items: center; margin-top: 3rem; div.view { margin-top: 3rem; } `; export const MyInput = ({ value, handleValueChange }) => { const inputEl = useRef(null); const [isEditMode, setEditMode] = useState(false); const [newValue, setNewValue] = useState(value); useEffect(() => { if (isEditMode) { inputEl.current.focus(); } }, [isEditMode]); useEffect(() => { setNewValue(value); }, [value]); const handleClick = () => { // TODO : isEditMode 상태를 변경합니다. setEditMode(!isEditMode) }; const handleBlur = () => { // TODO : Edit가 불가능한 상태로 변경합니다. handleValueChange(newValue); setEditMode(false) }; const handleInputChange = (e) => { // TODO : 저장된 value를 업데이트합니다. setNewValue(e.target.value) }; return ( <InputBox onClick={handleClick}> {isEditMode ? ( <InputEdit type='text' value={newValue} ref={inputEl} onChange={handleInputChange} onBlur={handleBlur} // TODO : 포커스를 잃으면 Edit가 불가능한 상태로 변경되는 메소드가 실행되어야 합니다. // TODO : 변경 사항이 감지되면 저장된 value를 업데이트 되는 메소드가 실행되어야 합니다. /> ) : ( <div onClick={handleClick} // TODO : 클릭하면 Edit가 가능한 상태로 변경되어야 합니다. >{newValue}</div> )} </InputBox> ); } const cache = { name: '김코딩', age: 20 }; export const ClickToEdit = () => { const [name, setName] = useState(cache.name); const [age, setAge] = useState(cache.age); return ( <> <InputView> <label>이름</label> <MyInput value={name} handleValueChange={(newValue) => setName(newValue)} /> </InputView> <InputView> <label>나이</label> <MyInput value={age} handleValueChange={(newValue) => setAge(newValue)} /> </InputView> <InputView> <div className='view'>이름 {name} 나이 {age}</div> </InputView> </> ); };
반응형'Topic > React | Redux' 카테고리의 다른 글
Virtual Dom의 정의와 장점 (0) 2022.05.22 Redux, React, action, reducer, store (0) 2022.01.07 React, 컴포넌트 디자인, styled-component 적용 (0) 2022.01.04 REACT 컴포넌트 디자인, CDD, Storybook, useRef, Styled-Component (0) 2022.01.03 [정리] REACT, 데이터 흐름의 이해와 비동기 (0) 2021.12.31