기존 VanillaJS를 활용하여 filesystem을 구현하는 것에 비해, React 기반의 filesystem은 어떠한 장점이 있는지 살펴본다.
사용자가 로그인을 하면 로그인 정보에 맞춰 data를 유지 및 load 한다.
Routing 구조를 구성한다.
import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Home from '../routes/Home.js';
import Detail from '../routes/Detail.js';
function App() {
return (
<Router>
<Routes>
<Route path="/" exact={true} element={<Home/>} />
<Route path="/:userID" element={<Detail/>}/>
</Routes>
</Router>
);
}
export default App;
사용자가 입력한 data를 localStorage를 임시 저장소로 활용하여 전달한다.
const [userID, setUserID] = useState('');
const [userPW, setUserPW] = useState('');
setUserID(value);
setUserPW(value);
<input type='text' placeholder="ID" value={userID} onChange={updateUserID}/>
<input type='password' placeholder="PW" value={userPW} onChange={updateUserPW}/>
<Link to={{
pathname: `/${userID}`
}} onClick={() => saveStateValues(userID, userPW)}>로그인하기</Link>
Home.js의 전체 구성
import React, {useState} from 'react';
import {Link} from 'react-router-dom';
import {gql, useQuery} from '@apollo/client';
import styled from 'styled-components';
const dataContext = React.createContext();
const Container = styled.div`
`
const Title = styled.h1`
padding: 1%;
align-items: center;
`
const UserInformation = styled.div`
display: flex;
`
function Home() {
const [userID, setUserID] = useState('');
const [userPW, setUserPW] = useState('');
const updateUserID = e => {
const {target : {value}} = e;
//value 변수 자체는 문자 하나하나
//각각 입력될때마다 반응
setUserID(value);
//이 입력되는 값들에 대해
//상태관리화하면 (누적된) 상태관리가 가능해진다.
console.log(userID);
};
const updateUserPW = e => {
const {target : {value}} = e;
//value 변수 자체는 문자 하나하나
//각각 입력될때마다 반응
setUserPW(value);
//이 입력되는 값들에 대해
//상태관리화하면 (누적된) 상태관리가 가능해진다.
console.log(userPW);
};
const saveStateValues = (userID, userPW) => {
localStorage.setItem(userID, userPW);
};
return(
<Container>
<Title>사용자 로그인</Title>
<UserInformation>
<input type='text' placeholder="ID" value={userID} onChange={updateUserID}/>
<input type='password' placeholder="PW" value={userPW} onChange={updateUserPW}/>
</UserInformation>
<Link to={{
pathname: `/${userID}`
}} onClick={() => saveStateValues(userID, userPW)}>로그인하기</Link>
</Container>
)
};
export default Home;
이벤트를 구성하는 경우 작성형태에 유의한다.
data 저장소 및 hooks(useParams 등)을 통해 이전 component에서 data를 전달받는다.
const {userID} = useParams();
const userPW = localStorage.getItem(userID);
//const userIDByLocal = localStorage.key(userPW);
const [finalText, setFinalText] = useState('');
const [finalImage, setFinalImage] = useState('');
let txtDATA = localStorage.getItem(`${userID}fortxt`);
let imageDATA = localStorage.getItem(`${userID}forimg`);
setFinalText(text);
setFinalImage(fileRead.result);
{finalText? (<pre className="textArea" contentEditable>{finalText}</pre>) : (<div>NO SAVED TEXT DATA</div>)}
{finalImage? (<div className="imageAreaCover"><img className="imageArea" src={finalImage}></img></div>) : (<div>NO SAVED IMAGE DATA</div>)}
※ file system(외부 입출력)을 통해 data를 전달받는 과정에서 상태관리를 바로 적용하지는 않는다.
※ 최종적으로 text/image file을 입력받은 data에 대해 상태관리변수에 담고, 이를 return(화면구현)에 사용한다.
Detail.js의 전체 구성
import React, {useState} from 'react';
import { useParams } from 'react-router';
import styled from 'styled-components'
//import {useRef} from 'react-router-dom';
let fileRead = new FileReader();
const Container = styled.div`
`
function Detail(){
const {userID} = useParams();
const userPW = localStorage.getItem(userID);
//const userIDByLocal = localStorage.key(userPW);
const [finalText, setFinalText] = useState('');
const [finalImage, setFinalImage] = useState('');
let txtDATA = localStorage.getItem(`${userID}fortxt`);
let imageDATA = localStorage.getItem(`${userID}forimg`);
let fileBuffer = null;
async function fileOpenButton(){
[fileBuffer] = await window.showOpenFilePicker();
let fileData = await fileBuffer.getFile();
console.log(fileData);
if(fileData.type !== 'image/png'){
//interface file data
//await fileRead.readAsDataURL(fileData)
let text = await fileData.text();
localStorage.setItem(`${userID}fortxt`, text)
setFinalText(text);
return ;
}else if(fileData.type == 'image/png' || 'image/jpeg'){
//fileReader가 fileData를 먼저 읽어야 한다.
await fileRead.readAsDataURL(fileData);
fileRead.addEventListener('load', () => {
localStorage.setItem(`${userID}forimg` , fileRead.result);
setFinalImage(fileRead.result);
//console.log(fileRead.result);
//console.log(imageArea.src);
})
return;
//fileRead - null, fileRead.result - image URL.
//upload event를 부여할 경우에만 fileRead에서 data를 읽어올 수 있다.
}else{
return;
}
};
return(
<Container>
<button className="fileOpen" type="file" onClick={fileOpenButton}>파일 불러오기</button>
{finalText? (<pre className="textArea" contentEditable>{finalText}</pre>) : (
<div>NO SAVED TEXT DATA</div>)}
{finalImage? (<div className="imageAreaCover"><img className="imageArea" src={finalImage}></img></div>) : (
<div>NO SAVED IMAGE DATA</div>)}
<button className="fileSave">파일 저장하기</button>
<button className="fileSaveAs">다른 이름으로 파일 저장하기</button>
</Container>
)
}
export default Detail;
별도의 화면 랜더링이 필요할 경우, 이에 대한 Component를 구성하고 분기처리를 통해 return(화면구현) 한다.
React event 처리하기
https://ko.reactjs.org/docs/handling-events.html