npm i react-dropdown
import Dropdown from 'react-dropdown';
import 'react-dropdown/style.css';
...
const options = [
'one', 'two', 'three'
];
const defaultOption = options[0];
...
<Dropdown options={options} value={defaultOption} placeholder="Select an option" />
react-dropdown에서 css를 위한 추가 옵션들을 확인 가능하다
<button onClick={openStartTimeDropDown}>클릭</button>
<article
className={
`components-dropdown ${dropdownVisibility
? 'slide-fade-in-dropdown'
: 'slide-fade-out-dropdown'}`}
>
{dropdownVisibility ?
<ul>
{infos.map((info) => {
let data = (
<li key={info} onClick={selectStartTime(info)}>
{info}
</li>
);
return data;
})}
</ul>
: null}
</article>
/* drop down animation */
@keyframes slide-fade-in-dropdown-animation {
0% {
transform: translateY(-100%);
}
100% {
transform: translateY(0);
}
}
.slide-fade-in-dropdown {
overflow: hidden;
}
.slide-fade-in-dropdown > * {
animation: slide-fade-in-dropdown-animation .4s ease;
float: inline-start;
}
/* fade out */
@keyframes slide-fade-out-dropdown-animation {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-100%);
}
}
.slide-fade-out-dropdown {
overflow: hidden;
}
.slide-fade-out-dropdown > * {
animation: slide-fade-out-dropdown-animation 0.4s ease;
animation-fill-mode: forwards;
}
.components-dropdown > div {
position: relative;
}
.components-dropdown > ul > li{
list-style: none;
background-color: #fff;
position: relative;
padding-top: 0.2em;
}
.components-dropdown > ul > li:hover{
background-color: gray;
color: #fff;
}
.components-dropdown > ul {
height: 10em;
overflow-x: scroll;
margin: 0;
padding: 0;
}
npm i react-modal
import Modal from 'react-modal';
...
let subtitle;
const [modalIsOpen, setIsOpen] = useState(false);
function openModal() {
setIsOpen(true);
}
function afterOpenModal() {
// references are now sync'd and can be accessed.
subtitle.style.color = '#f00';
}
function closeModal() {
setIsOpen(false);
}
...
<button onClick={openModal}>Open Modal</button>
<Modal
isOpen={modalIsOpen}
onAfterOpen={afterOpenModal}
onRequestClose={closeModal}
contentLabel="Example Modal"
>
<h2 ref={(_subtitle) => (subtitle = _subtitle)}>Hello</h2>
<button onClick={closeModal}>close</button>
<div>I am a modal</div>
<form>
<input />
<button>tab navigation</button>
<button>stays</button>
<button>inside</button>
<button>the modal</button>
</form>
</Modal>
react-modal에서 기타 사용법등을 확인 가능하다
App.js
import Modal from './modal'
...
const [detailOpen, setDetailOpen] = useState(false)
const [data, setData] = useState()
const openDetail = () =>{
setDetailOpen(true)
}
const closeDetail = () =>{
setDetailOpen(false)
}
...
<button onClick={openDetail()}>Open</button>
<Modal open={ detailOpen } close={ closeDetail }/>
</div>
Modal.js
const { open, close } = props;
...
{open ? (
<section>
<header>
추가하기
<button className="close" onClick={close}>×</button>
</header>
<div>
</div>
<footer>
<button className="close" onClick={close}>
close
</button>
</footer>
</section>
) : null}
.modal {
display: none;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 99;
background-color: rgba(0, 0, 0, 0.6);
}
.modal > button {
outline: none;
cursor: pointer;
border: 0;
}
.modal > section {
width: 90%;
max-width: 450px;
margin: 0 auto;
border-radius: 0.3rem;
background-color: #fff;
/* 팝업이 열릴때 스르륵 열리는 효과 */
animation: modal-show 0.3s;
overflow: hidden;
}
.modal > section > header {
position: relative;
padding: 16px 64px 16px 16px;
background-color: #f1f1f1;
font-weight: 700;
}
.modal > section > header button {
position: absolute;
top: 15px;
right: 15px;
width: 30px;
font-size: 21px;
font-weight: 700;
text-align: center;
color: #999;
background-color: transparent;
}
.modal > section > main {
padding: 16px;
border-bottom: 1px solid #dee2e6;
border-top: 1px solid #dee2e6;
}
.modal > section > footer {
padding: 12px 16px;
text-align: right;
}
.modal > section > footer button {
padding: 6px 12px;
color: #fff;
background-color: #6c757d;
border-radius: 5px;
font-size: 13px;
}
.modal.openModal {
display: flex;
align-items: center;
/* 팝업이 열릴때 스르륵 열리는 효과 */
animation: modal-bg-show 0.3s;
}
@keyframes modal-show {
from {
opacity: 0;
margin-top: -50px;
}
to {
opacity: 1;
margin-top: 0;
}
}
@keyframes modal-bg-show {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
위 두 코드를 재작성시에는 라이브러리에 위 css를 조금 첨가하여 사용할 것 같다.
하지만 react를 처음 접하는 나에게 2개의 코드를 통해 가능을 구현하는것이 react 구조를 이해하는데에 큰 도움이 되었으므로 한 번쯤은 꼭 사용해보기를 추천한다.
react =파일전송=> spring
react spring (파일저장)
const onChange = e =>{
const reader = new FileReader()
reader.readAsDataURL(e.target.files[0]);
setImgFile(e.target.files[0])
return new Promise((res)=>{
reader.onload = () =>{
setImg(reader.result)
res()
}
})
}
const onClick = async e => {
const formData = new FormData()
let imsiFileName = '';
formData.append('file',imgFile)
let options = {
headers: {
'Content-type': 'multipart/form-data'
},
withCredentials: true
};
try {
imsiFileName = await axios.post("http://localhost:18080/file/save",formData,options)
} catch (error) {
alert("에러 발생, 빈칸을 채워주세요_file")
}
// 테스트를 위해 별개의 axios로 분리하였습니다.
// 위는 file을 upload 하기위한 axios
// 아래는 file의 url을 DB에 저장하기 위한 별도의 axios 입니다
const data = {
imglink : imsiFileName.data
}
options = {
headers: {
'Content-Type': 'application/json'
},
withCredentials: true
};
try {
await axios.post("http://localhost:18080/loc/save",data,options)
window.location.replace("/loc")
} catch (error) {
alert("에러 발생, 빈칸을 채워주세요_loc")
}
}
...
<div className='pre-img'>
<img src={img?img:'https://via.placeholder.com/300'} alt='/300.png' />
</div>
<input className='input-img' type="file" onChange={onChange}/>
<button className='save-loc' onClick={onClick}>업로드</button>
FileController.java
@PostMapping("/save")
public String doSave(@RequestParam("file") MultipartFile file) {
log.info("/save : {}", file);
String fileName = file.getOriginalFilename();
String extension = fileName.substring(fileName.lastIndexOf("."), fileName.length());
UUID uuid = UUID.randomUUID();
String newFileName = uuid.toString() + extension;
log.info(">> {}", newFileName);
File targetFile = new File("src/main/resources/static/imgs/" + newFileName);
log.info(">> : {}", targetFile.getAbsolutePath());
try {
InputStream inputStream = file.getInputStream();
FileUtils.copyInputStreamToFile(inputStream, targetFile);
} catch (Exception e) {
FileUtils.deleteQuietly(targetFile);
log.error("error : ", e);
}
return newFileName;
}
react =요청 전송=> spring
react <=파일 전송= spring
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/imgs/**")
.addResourceLocations("classpath:/static/imgs/");
}
}
<img src={`http://localhost:18080/imgs/${imgurl}`} alt=''/>