-
React/DropdownSearch 만들기Language/React 2022. 12. 1. 09:54
간단한 검색이 가능한 dropdown을 만들려고 한다.
css
.g-dropdown-search-wrap { position: relative; } .g-dropdown-search-wrap > .search-section { display: flex; justify-content: flex-start; align-items: center; } .g-dropdown-search-wrap > .search-section input { width: 100%; padding: 12px 8px; border: 1px solid #D9D9D9; } .g-dropdown-search-wrap > .search-section input:focus { border: 1px solid #25B9B9; } .g-dropdown-search-wrap > .search-section button { border: 1px solid #D9D9D9; cursor: pointer; border-left-width: 0; } .g-dropdown-search-wrap > .dropdown-list { display: flex; flex-direction: column; justify-content: center; align-items: flex-start; position: absolute; left: 0; z-index: 10; border-radius: 2px; background: #FFFFFF; cursor: pointer; box-shadow: 0px 3px 6px -4px rgba(0, 0, 0, 0.12), 0px 6px 16px rgba(0, 0, 0, 0.08), 0px 9px 28px 8px rgba(0, 0, 0, 0.05); } .g-dropdown-search-wrap > .dropdown-list > .option { width: 100%; height: 32px; padding: 5px 12px; color: rgba(0, 0, 0, 0.65); font-weight: 400; font-size: 14px; line-height: 22px; } .g-dropdown-search-wrap > .dropdown-list > .option:hover { background: #4db8ff; color: white; }
부모 compoent
import React, { Component } from 'react'; ... class ListBase extends Component { ... state = { ... dropdown: { key: '', text: '', show: false, items: [], }, }; refTab1 = React.createRef(); refTab2 = React.createRef(); refTab3 = React.createRef(); init = () => { this.fetchDropdown({ key: this.state.dropdown.key, text: this.state.dropdown.text }); }; ... fetchDropdown = (item) => { this.setDelay(() => { Loading.enable(false); const params = { SEARCH_TEXT: item.text, HOST_MEMBER_ID: this.hostMemberId }; Request.get('/contracts/simple?' + JSON.stringify(params)).then((response) => { Loading.enable(true); const dropdownItems = []; for (const item of response.DATA) { // dropdownItems.push({ key: item.CONTRACT_ID, text: `${item.GUEST_NAME} (${item.HP_NO})` }); dropdownItems.push({ key: item.CONTRACT_ID, text: `${item.GUEST_NAME}` }); } const theDropdown = { ...this.state.dropdown }; theDropdown.items = dropdownItems; this.setState({ dropdown: theDropdown, }); }); }, 500); }; dropdownSearchTimer = null; setDelay = (callback, ms) => { clearTimeout(this.dropdownSearchTimer); this.dropdownSearchTimer = setTimeout((args) => { callback.apply(this, args); }, ms || 0); }; fetchAll = () => { this.refTab1.current.fetchAll(); this.refTab2.current.fetchAll(); this.refTab3.current.fetchAll(); }; render() { ... return ( <div id="gundam-container"> <div className="page-header"> ... </div> <div className="search-wrap"> <div className="search-form"> <div className="row" style={{ marginBottom: '16px' }}> <dl> <dt> <i className="search-line-gray85-16"></i> 통합검색 </dt> <dd> <DropdownSearch class="g-dropdown-search-wrap" styles={{ height: '40px', // height: 'auto', }} icon={{ class: 'search-line-gray85-16', width: '40px', height: '40px', }} placeholder="계약자명, 휴대폰번호 입력" selectedKey={this.state.dropdown.key} selectedText={this.state.dropdown.text} show={this.state.dropdown.show} onDropdownSearch={(item) => { const theDropdown = { ...this.state.dropdown }; theDropdown.key = item.key; theDropdown.text = item.text; this.setState({ dropdown: theDropdown }, () => { this.fetchDropdown(item); }); }} onSearch={(item) => { const theDropdown = { ...this.state.dropdown }; theDropdown.key = item.key; theDropdown.text = item.text; this.setState({ dropdown: theDropdown }, () => { this.fetchAll(); }); }} items={this.state.dropdown.items} /> </dd> </dl> </div> </div> </div> ... </div> ); } } export default wrapWithBase(ListBase);
DropdownSearch
import React, { useEffect, useState, useRef, useCallback } from 'react'; const DropdownSearch = (props) => { const [data, setData] = useState({ key: props.selectedKey ?? '', text: props.selectedText ?? '', show: props.show ?? false, }); // useEffect(() => { // console.log('마운트 될 때만 실행'); // }, []); // useEffect(() => { // console.log('렌더링 될 때마다 실행'); // }); // useEffect(() => { // console.log('data가 업데이트 될 때마다 실행'); // console.log('Do something after data has changed', data); // }, [data]); useEffect(() => { // data.key 가 변경되었을때 호출 if (data.show === true) { props.onSearch({ key: data.key, text: data.text }); } }, [data.key]); const classWrap = props.class ?? 'g-dropdown-search-wrap'; const styles = props.styles; const height = styles?.height ?? 'auto'; const placeholder = props.placeholder ?? '검색어를 입력하세요.'; const resultWrapStyle = props.icon && { width: 'calc(100% - 40px)' }; const handleChange = (key) => { setData((prevState) => ({ ...prevState, ...key, })); }; return ( <> <div className={classWrap}> <div className="search-section"> <input // ref={searchInput} placeholder={placeholder} style={{ height: height }} value={data.text ?? ''} onChange={(e) => { handleChange({ text: e.target.value }); }} onClick={() => { handleChange({ show: !data.show }); }} onKeyUp={(e) => { if (e.key === 'Enter') { props.onSearch({ key: '', text: data.text }); handleChange({ show: false }); } else { props.onDropdownSearch({ key: '', text: e.target.value }); handleChange({ show: true }); } }} onBlur={(e) => { if (e.nativeEvent.explicitOriginalTarget && e.nativeEvent.explicitOriginalTarget === e.nativeEvent.originalTarget) { return; } if (data.show) { setTimeout(() => { handleChange({ show: false }); }, 200); } }} /> {(() => { if (props.icon) { const iconClass = props.icon.class; const iconWidth = props.icon.width; const iconHeight = props.icon.height; return ( <> <button style={{ width: iconWidth, height: iconHeight }} onClick={() => { props.onSearch({ key: data.key, text: data.text }); }} > <i className={iconClass}></i> </button> </> ); } })()} </div> <ul className="dropdown-list" style={resultWrapStyle} hidden={!data.show}> {props.items.map((item, index) => ( <li key={item.key} className="option" onClick={(e) => { handleChange({ key: item.key, text: item.text }); // useEffect 에서 검색처리 // props.onSearch({ key: index, text: item }); }} > {item.text} </li> ))} </ul> </div> </> ); }; export default DropdownSearch;
참조)
https://codepen.io/quafoo/pen/jONdwWG
'Language > React' 카테고리의 다른 글
React/RadioButton Component 만들기 (0) 2022.12.01 React/X-Bar chart 만들기 (0) 2022.12.01 React/moment 사용 탐방 (0) 2022.10.21 React/memory leak - componentWillUnmount Event 제거 이슈 (0) 2022.10.19 React/createContext, useContext 사용하기 (0) 2022.10.12