leemember / fe_growing Goto Github PK
View Code? Open in Web Editor NEW๐ง๐ปโ๐พ TIL Record Repo & FE ์ค๋ฌด์์ ๋ง์ฃผ ํ๋ ํธ๋ฌ๋ธ ์ํ ๊ณผ ๊ฒฝํ ์ ๋ฌ๋ ํฌ์ธํธ
๐ง๐ปโ๐พ TIL Record Repo & FE ์ค๋ฌด์์ ๋ง์ฃผ ํ๋ ํธ๋ฌ๋ธ ์ํ ๊ณผ ๊ฒฝํ ์ ๋ฌ๋ ํฌ์ธํธ
๋ธ๋ผ์ฐ์ ์์ฒด์ ๋ด์ฅ๋์ด์๋ JS ์์ง์ด ํ์ํ๋ค. ์ด๊ฒ์ด ๋์ํ๋ ์๊ฐ์ ๋ฐํ์์ด๋ผ๊ณ ํ๋๋ฐ ๋ฐํ์ ํ๋ ๊ณผ์ ์์ ์ฝ๋๋ฅผ ํ ์ค ํ ์ค ์ฝ๊ณ ๋ฒ์ญํด์ ์คํ์ ํด์ฃผ๋ ๊ฒ์ด ์ธํฐํ๋ฆฌํฐ ๋ผ๊ณ ํ๋ค. ๋ณดํต ๋ค๋ฅธ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์์๋ ์ปดํ์ผ๋ฌ๊ฐ ํ์ํ๋ค. ์ปดํ์ผ๋ฌ๊ฐ ๋์ํ๋ ๋ฐฉ์์ ์๋ฐ๋ก ์๋ฅผ ๋ค๋ฉด, ์ฐ๋ฆฌ๊ฐ ์์ฑํ ์ฝ๋๋ฅผ ๋ฐ๋ก ์คํํ ์ ์๋ ๊ฒ์ ์๋๊ณ ์คํํ๊ธฐ ์ ๋ชจ๋ ์ฝ๋๋ฅผ ์ปดํ์ผ๋ง ํ์ฌ ์ปดํจํฐ์์ ์คํํ ์ ์๋๋ก ํ๋ค.
์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ๊ธฐ ์ํด์๋ ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ด ํ์ํ๊ณ ๊ฐ๊ฐ์ ๋ธ๋ผ์ฐ์ ๋ง๋ค ๊ฐ๊ธฐ ๋ค๋ฅธ ์์ง์ ๊ฐ์ง๊ณ ์๊ณ ๊ทธ ๋ฒ์ ๋ณ๋ก ์๋๋๋ ๊ฒ๋ ๋ค ๋ค๋ฅด๋ค.
๋ฒ์ 5์์ strict mode์ getter, setter๊ฐ ์ถ๊ฐ๋๋ค.
์ด๋ ๋ฏ ๋ฒ์ ์ด ์๋ก์์ง๋ฉด ์ถ๊ฐ๋ ๊ฒ ๊ธฐ๋ฅ๋ค๋ ๊ฐ๊ธฐ ๋ค๋ฅด๊ธฐ ๋๋ฌธ์, ๋ฐ๋ฒจ์ ์ฌ์ฉํ๋ค.
๋ฐ๋ฒจ์ ์ฌ์ฉํ๋ฉด ๋ฒ์ ์ ๊ฒฝ ์์ฐ๊ณ ์ฌ์ฉํ ์ ์๋ค.
์๋ฐ์คํฌ๋ฆฝํธ๋ ๊ฐ๋ณ๊ณ ์ธํฐํ๋ฆฌํฐ๋ฅผ ์ด์ฉํด์ ๋ฐํ์ ์ ํ ์ค ํ ์ค ๋ฒ์ญํ๋ค.
์ผ๊ธ ํจ์๋ฅผ ๊ฐ์ง ์ธ์ด์ด๋ค. ์๋ฐ์คํฌ๋ฆฝํธ ์์ง์ด ์๋ ์ด๋ค ๊ณณ์ด๋ ์ฌ์ฉํ ์ ์๋ค.
์๋ฐ์คํฌ๋ฆฝํธ๋ ํ๋กํ ํ์
์ ๋ฒ ์ด์ค๋ก ๋ค์ํ ์คํ์ผ๋ก ๊ตฌํ์ด ๊ฐ๋ฅํ๊ณ ๋ฉํฐ ํ๋ฌ๋ค์์ด๋ค. ์ ์ฐจ์งํฅ์ผ๋ก๋ ๊ฐ๋ฅํ๊ณ ๊ฐ์ฒด์งํฅ์ผ๋ก๋ ๊ฐ๋ฅํ๋ค. ์ฑ๊ธ ์ฐ๋ ๋๊ณ , ๋ค์ด๋๋ฏนํ ์ธ์ด์ด๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ์ธ์ด ์์ฒด๋ง์ผ๋ก๋ ํ ์ ์๋ ๊ฒ์ด ๊ทธ๋ฆฌ ๋ง์ง ์๋ค.
๋ธ๋ผ์ฐ์ ์ ๋ฌด์ธ๊ฐ๋ฅผ ์ถ๋ ฅํ๊ณ ์ถ๋ค๋ฉด ์ธ๋ถํ๊ฒฝ์ ์ถ๋ ฅ ํ ๋งํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
๊ทธ๋ฆฌ๊ณ ๋คํธ์ํฌ ํต์ ์ ํ๋ ค๋ฉด ํต์ ์ ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
์ด์ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ธ๋ผ์ฐ์ ์ ๋์ํ๊ณ ์ ํ๋ค๋ฉด ํ๋ก ํธ์๋ ์ง์์ด ์์ด์ผํ๋ค.
์ด์ ๊ฐ์ ์ง์๋ค๋ ํ์ํ๋ค. ์๋ฐ์คํฌ๋ฆฝํธ๋ ๊ทธ๋ฅ ์ธ์ด์ผ ๋ฟ์ด๋ค.
์๋ฐ์คํฌ๋ฆฝํธ๋ฅผ ์ํ๋ฉด ๋ธ๋ผ์ฐ์ ์ ๋
ธ๋ JS๋ฅผ ๋๋๋ค๋ฉฐ ํ๋ก ํธ์ ๋ฐฑ์๋๋ ๋ฅ์๋ฅ๋ํ๊ฒ ๋ค๋ฃฐ ์ ์๋ค.
์ฟ ํค๋ ํด๋ผ์ด์ธํธ(๋ธ๋ผ์ฐ์ ) ๋ก์ปฌ์ ์ ์ฅ๋๋ ํค์ ๊ฐ์ด ๋ค์ด์๋ ์์ ๋ฐ์ดํฐ ํ์ผ์
๋๋ค.
์ฌ์ฉ์ ์ธ์ฆ์ด ์ ํจํ ์๊ฐ์ ๋ช
์ํ ์ ์์ผ๋ฉฐ, ์ ํจ ์๊ฐ์ด ์ ํด์ง๋ฉด ๋ธ๋ผ์ฐ์ ๊ฐ ์ข
๋ฃ๋์ด๋ ์ธ์ฆ์ด ์ ์ง๋๋ค๋ ํน์ง์ด ์์ต๋๋ค.
์ฟ ํค๋ ํด๋ผ์ด์ธํธ์ ์ํ ์ ๋ณด๋ฅผ ๋ก์ปฌ์ ์ ์ฅํ๋ค๊ฐ ์ฐธ์กฐํฉ๋๋ค.
ํด๋ผ์ด์ธํธ์ 300๊ฐ๊น์ง ์ฟ ํค์ ์ฅ ๊ฐ๋ฅ, ํ๋์ ๋๋ฉ์ธ๋น 20๊ฐ์ ๊ฐ๋ง ๊ฐ์ง ์ ์์, ํ๋์ ์ฟ ํค๊ฐ์ 4KB๊น์ง ์ ์ฅํฉ๋๋ค.
Response Header
์ Set-Cookie
์์ฑ์ ์ฌ์ฉํ๋ฉด ํด๋ผ์ด์ธํธ์ ์ฟ ํค๋ฅผ ๋ง๋ค ์ ์์ต๋๋ค.
์ฟ ํค๋ ์ฌ์ฉ์๊ฐ ๋ฐ๋ก ์์ฒญํ์ง ์์๋ ๋ธ๋ผ์ฐ์ ๊ฐ Request์์ Request Header๋ฅผ ๋ฃ์ด์ ์๋์ผ๋ก ์๋ฒ์ ์ ์กํฉ๋๋ค.
์ด๋ฆ : ๊ฐ๊ฐ์ ์ฟ ํค๋ฅผ ๊ตฌ๋ณํ๋ ๋ฐ ์ฌ์ฉ๋๋ ์ด๋ฆ
๊ฐ : ์ฟ ํค์ ์ด๋ฆ๊ณผ ๊ด๋ จ๋ ๊ฐ
์ ํจ์๊ฐ : ์ฟ ํค์ ์ ์ง์๊ฐ
๋๋ฉ์ธ : ์ฟ ํค๋ฅผ ์ ์กํ ๋๋ฉ์ธ
๊ฒฝ๋ก : ์ฟ ํค๋ฅผ ์ ์กํ ์์ฒญ ๊ฒฝ๋ก
์ฟ ํค์ ๋์ ๋ฐฉ์
ํด๋ผ์ด์ธํธ๊ฐ ํ์ด์ง๋ฅผ ์์ฒญ
์๋ฒ์์ ์ฟ ํค๋ฅผ ์์ฑ
HTTP ํค๋์ ์ฟ ํค๋ฅผ ํฌํจ ์์ผ ์๋ต
๋ธ๋ผ์ฐ์ ๊ฐ ์ข
๋ฃ๋์ด๋ ์ฟ ํค ๋ง๋ฃ ๊ธฐ๊ฐ์ด ์๋ค๋ฉด ํด๋ผ์ด์ธํธ์์ ๋ณด๊ดํ๊ณ ์์
๊ฐ์ ์์ฒญ์ ํ ๊ฒฝ์ฐ HTTP ํค๋์ ์ฟ ํค๋ฅผ ํจ๊ป ๋ณด๋
์๋ฒ์์ ์ฟ ํค๋ฅผ ์ฝ์ด ์ด์ ์ํ ์ ๋ณด๋ฅผ ๋ณ๊ฒฝ ํ ํ์๊ฐ ์์ ๋ ์ฟ ํค๋ฅผ ์
๋ฐ์ดํธ ํ์ฌ ๋ณ๊ฒฝ๋ ์ฟ ํค๋ฅผ HTTP ํค๋์ ํฌํจ์์ผ ์๋ต
๋ฐฉ๋ฌธ ์ฌ์ดํธ์์ ๋ก๊ทธ์ธ ์, "์์ด๋์ ๋น๋ฐ๋ฒํธ๋ฅผ ์ ์ฅํ์๊ฒ ์ต๋๊น?"
์ผํ๋ชฐ์ ์ฅ๋ฐ๊ตฌ๋ ๊ธฐ๋ฅ
์๋๋ก๊ทธ์ธ, ํ์
์์ "์ค๋ ๋ ์ด์ ์ด ์ฐฝ์ ๋ณด์ง ์์" ์ฒดํฌ, ์ผํ๋ชฐ์ ์ฅ๋ฐ๊ตฌ๋
์ฐธ๊ณ : https://kotlinworld.com/266
git config --global user.name "[user name]"
git config --global user.email "[user emial]"
git config --local user.name "[user name]"
git config --local user.email "[user emial]"
antd ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉํ์๊ณ ์ปดํฌ๋ํธ๋ datePicker ์ฌ์ฉํ๋ค.
์ค๋ ๋ ์ง ์ดํ๋ก ๋ฏธ๋ ๋ ์ง๋ฅผ ํด๋ฆญํ์ง ๋ชปํ๊ฒ ๋นํ์ฑํ ์ํค๋ ๋ฐฉ๋ฒ์
์๋์๊ฐ์ด ์์
ํ๋ฉด ๋๋ค.
<DatePicker
onChange={onChange}
className="dataInput"
defaultValue={moment(today, 'YYYY-MM-DD')}
๐disabledDate={(current: any) => {
const start: any = moment('2020-01-01', 'YYYY-MM-DD');
return current < start || current > moment();
}}
/>
์ฝ๋ํ ์์ ์ฝ๋
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import { DatePicker } from 'antd';
function disabledYear(current) {
// return current.year() === 2021; // disabling 2021
// return current.year() !== 2021; // disabling everything besides 2021
// return current.year() !== (new Date).getFullYear(); // disabling everything besides current year
// return current.year() > 2021; // disabling everything further than 2021
return current.year() < 2021; // disabling everything in the past before 2021
return [2018, 2019].includes(current.year()); // disabling 2018 and 2019
}
ReactDOM.render(
<div>
<DatePicker format="YYYY-MM-DD" disabledDate={disabledYear} />
</div>,
document.getElementById('root')
);
๐ต ์ค์ ๊ตฌํํด๋ณธ ์ฝ๋
<DatePicker
onChange={onChangeDate}
className="dataInput"
format="YYYY-MM-DD"
disabledDate={(current: any) => {
return current.year() < 2020 || current >= moment().subtract(1, 'days').toDate();
}}
/>
์ฐธ๊ณ https://stackoverflow.com/questions/46358603/disable-date-and-time-for-antd-datepicker
https://ant.design/components/date-picker/#header
$npm i react-hot-loader
์ค์นํ๊ธฐ
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Board1 from './pages/board1';
import Board2 from './pages/board2';
import { hot } from 'react-hot-loader';
const App = () => {
return (
<Router>
<Routes>
<Route path="/" element={<Board1 />} />
<Route path="/board2" element={<Board2 />} />
</Routes>
</Router>
);
};
export default hot(module)(App);
๋ชจ๋ ๊ตฌ์ฑ ๋ณด๊ธฐ
git config --list #show all the settings in gitconfig
ํธ์งํ ๊ตฌ์ฑ ์ด๊ธฐ
git config --global -e #open .gitconfig file
๊ธฐ๋ณธ ํธ์ง๊ธฐ ์ค์
git config --global core.editor "code --wait" # set default text editor for git
์ฌ์ฉ์ ์ค์
git config --global user.name "name" #set user.name
git config --global user.email "email" #set user.email
git config user.name #check user.name
git config user.email #check user.email
์๋ CRLF ์ค์
git config --global core.autocrlf true #for Windows
git config --global core.autocrlf input #for Mac
Git Aliases
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
Git official site
See help
git config --help #detail
git config -h #short
git init #initialise git
rm -rf .git #delete .git
git status #full status
git status -s #short status
Add files that should be ignored in .gitignore in project directory
For example:
# ignore all .a files
*.a
# but do track lib.a, even though you're ignoring .a files above
!lib.a
# only ignore the TODO file in the current directory, not subdir/TODO
/TODO
# ignore all files in any directory named build
build/
# ignore doc/notes.txt, but not doc/server/arch.txt
doc/*.txt
# ignore all .pdf files in the doc/ directory and any of its subdirectories
doc/**/*.pdf
git add a.txt #stage a.txt file
git add a.txt b.txt #stage a.txt, b.txt files
git add *.txt #stage all files ends with .txt
git add * #stage all files except deleted files and files that begin with a dot
git add . #stage everything
Removing files
rm file.txt #delete file
git add file.txt #add to staging area
git rm file.txt # removes file from working directory and staging area
git rm --cached file.txt #removes from staging area only
git clean -fd #removes all untracked files
Moving files
git mv from.txt to.txt
git mv from.text /logs/from.text
git status #full status
git status -s #short status
git diff #changes in working directory
git diff --staged #changes in staging area
git diff --cached #same as --staged
Open .gitconfig and add below
[diff]
tool = vscode
[difftool "vscode"]
cmd = code --wait --diff $LOCAL $REMOTE
Run Git Diff tool
git difftool
git commit #commit stagged files
git commit -m "Commit message" #commit stagged files with commit message
git commit -am "Commit message" #commit all files with commit message
git log #list of commits
git log --patch #shows the difference introduced in each commit
git log -p #same as --patch
git log --state #abbreviated states for each commit
git log --oneline #oneline
git log --oneline --reverse #oneline, from the oldest to the newest
git log --pretty=oneline #same as --oneline
git log --pretty=format:"%h - %an %ar %s" #formatting
git log --pretty=format:"%h %s" --graph #show graph
git log --graph --all --pretty=format:'%C(yellow)[%ad]%C(reset) %C(green)[%h]%C(reset) | %C(white)%s %C(bold red){{%an}}%C(reset) %C(blue)%d%C(reset)' --date=short
git log -2 #shows only the last n commits
git log --author="ellie"
git log --before="2020-09-29"
git log --after="one week ago"
git log --grep="message" #finds in commit messages
git log -S="code" #finds in the code
git log file.txt #logs only for file.txt
git log file.txt #history of file.txt
git log --state file.txt #shows statistics
git log --patch file.txt #show the changes
git log HEAD
git log HEAD~1
git log hash
git show HEAD #shows the last commit
git show hash #shows the given commit
git show hash:file.txt
git diff hash1 hash2 #all changes between two commits
git diff hash1 hash2 file.txt #changes to file.txt only
git tag v1.0.0 #lightweight tag on latest commit
git tag v1.0.0 hash #lightweight tag on the given commit
git show v.0.0 #shows the tag
git tag -a v.1.0.0 -m "message" #annotated tag
git tag #all the tags
git tag -l "v1.0.*" #search certain tags
git tag -d v1.0.0 #delete the given tag
git push origin v1.0.0 #sharing the given tag with remote
git push origin --tags #sharing all the tags
git push origin --delete v1.0.0 #delete a remote tag
git checkout v1.0.0 #checkout certain tag
git checkout -b branchName v1.0.0 #create a new bracnh with the given tag
git branch testing #create a new branch called testing
git checkout testing #switches to testing branch
git switch testing #same as the above
git checkout -b testing #create and switch to testing
git switch -C testing #same as the above
git branch #simple listing of all branches
git branch -r #sees the remote branches
git branch --all #list including remote branches
git branch -v #sees the last commit on each branch
git branch --merged #sees merged branches
git branch --no-merged #sees not merged branches
git branch -d testing #deletes the branch
git push origin --delete testing
git branch --move wrong correct #rename
git push --set-upstream origin correct #push new name
git log branch1..branch2 #all the commits between branch1 and branch2
git diff branch1..branch2 #all the changes between branch1 and branch2
git merge featureA #merges featureA branch into the current one
git merge --squash featureA #suqash merge, only one commit
git merge --no-ff featureA #creates a merge commit
git merge --continue
git merge --abort
git mergetool #opens merge tool
Merge tool Config
[merge]
tool = vscode
[mergetool]
keepBackup = false
[mergetool "vscode"]
cmd = code --wait $MERGED
[mergetool "p4merge"]
path = "/Applications/p4merge.app/Contents/MacOS/p4merge"
git rebase master #rebase current branch onto the master
git rebase --onto master service ui #take commits of the ui branch forked from the service branch and move them to master
git cherry-pick hash #applies the given commit
git stash push -m "message" #make a new stash
git stash #same as above
git stash --keep-index #stash but keep them in the staging area
git stash -u #--include-untracked
git stash list #see all the stashes
git stash show hash #see the given stash
git stash show hash -p #see the given stash with details
git stash apply hash #applies the given stash
git stash apply #applies the latest stash
git stash apply --index #apply the stated changes
git stash pop #apply and drop
git stash branch branchName #apply stash in a new branch
git stash drop hash #deletes the given stash
git stash clear #deletes all the stashes
Unstaging a staged file
git reset HEAD file.txt
Unmodifying a modified file
git checkout -- file.txt
Discarding local changes
git restore --staged file.txt #unstaging a staged file
git restore file.txt #unmodifying a modified file
git restore . #unmodifying all modified files in the directory
git clean -fd #removes all untracked files
Restoring file from certain commit
git restore --source=hash file.txt
git restore --source=HEAD~2 file.txt
Amending the last commit
git commit --amend
git reset --soft HEAD # ์ค๋น ์์ญ์์ ์ปค๋ฐ ๋ฐ ์ ์ง ๋ณ๊ฒฝ ์ฌํญ์ ์ ๊ฑฐํฉ๋๋ค.
git reset --mixed HEAD # ์์
๋๋ ํฐ๋ฆฌ์์ ์ปค๋ฐ ๋ฐ ์ ์ง ๋ณ๊ฒฝ ์ฌํญ์ ์ ๊ฑฐํฉ๋๋ค.
git reset --hard HEAD # ์ปค๋ฐ์ ์ ๊ฑฐํ๊ณ ์ฝ๋๋ฅผ ์ ์งํ์ง ์์
git reflog
git reset --hard hash
git revert hash # ์ง์ ๋ ์ปค๋ฐ์ ๋๋๋ฆฝ๋๋ค.
git revert HEAD~1
git revert --no-commit hash # ์ปค๋ฐ ๋๋๋ฆฌ๊ธฐ ์์ด ์ง์ ๋ ์ปค๋ฐ์ ๋๋๋ฆฝ๋๋ค.
git rebase -i HEAD~2
git rebase --continue
git rebase --abort
git clone URL #cloning
git remote -v #shows all the remote URLs
git remote add name URL #add a new remote with name
Inspecting
git remote
git remote show
git remote show origin
Syncing with remotes
git fetch #pulls down all the data from remote
git fetch origin #same as the above
git fetch origin master #pulls down only master branch
git pull #fetch and merge
git pull --rebase #use rebase when pulling instead of merge
git push
git push origin master
Renaming or Removing
git remote rename sec second
git remote remove second
git blame file.txt
git bisect start
git bisect good hash
git bisect good
git bisect bad
git bisect reset
[alias]
s = status
l = log --graph --all --pretty=format:'%C(yellow)%h%C(cyan)%d%Creset %s %Cgreen(%cr) %C(magenta)<%an>%Creset'
up = !git fetch origin master && git rebase origin/master
co = checkout
ca = !git add -A && git commit -m
cad = !git add -A && git commit -m "."
c = commit
b = branch
list = stash list
save = stash save
pop = stash pop
apply = stash apply
rc = rebase โcontinue
get = "!f(){ git fetch && git checkout $1 && git reset --hard origin/$1; };f"
new = "!f(){ git co -b ellie-$1 origin/master && git pull; };f"
st = status
hist = log --graph --all --pretty=format:'%C(yellow)[%ad]%C(reset) %C(green)[%h]%C(reset) | %C(white)%s %C(bold red){{%an}}%C(reset) %C(blue)%d%C(reset)' --date=short
// ์คํฌ๋กค ์ด๋ฒคํธ์ ํด๋ฆญ ์ด๋ฒคํธ ์คํ์ ๋งํ์ ์ฌ๋ผ์ง๋๋ก
useEffect(() => {
window.addEventListener('scroll', handleScroll);
window.addEventListener('click', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
window.removeEventListener('click', handleScroll);
};
}, []);
// ์คํฌ๋กค, ํด๋ฆญ ์ด๋ฒคํธ
const handleScroll = (e) => {
// ์คํฌ๋กค ์, ์๋ฌด๊ณณ ํด๋ฆญ์ simpleTip ๋งํ์ ์ฌ๋ผ์ง๊ฒ
if (window.scrollY >= 100 || onModal && (!el.current || !el.current?.contains(e.target))){
setOnModal(false)
}
};
useEffect๋ฅผ ์ฌ์ฉํด์ ์คํฌ๋กค ์ด๋ฒคํธ๋ click ์ด๋ฒคํธ๊ฐ ์ผ์ด๋ ๋ handleScroll
์ด๋ผ๋ ํจ์๊ฐ ๋์๋๋๋ก ํ๋ค.
๊ทธ๋์ useEffect ๊ธฐ๋ฅ๋ด์ ์๋ retrun ๊ฐ์ ํตํด cleanup ์์
๊น์ง ํ๋ค. (removeEventListener
== ์ด๋ฒคํธ๋ฅผ ์ง์์ฃผ๋)
๊ทธ๋ฆฌ๊ณ ์๋น์ค ํดํ ๋งํ์ ์ด ์ฌ๋ผ์ง๋ ์กฐ๊ฑด์ 2๊ฐ์ง๋ค
๊ทผ๋ฐ ์์
ํ๋ฉด์ ๋ฌธ์ ์ ์ด ๋ฌด์์ด๋๋ฉด,
๋ฉ์ธํ์ด์ง์ ์ฒซ ๋ฒ์งธ๋ก ๋ํ๋๋ ๋ชจ๋ฌ์ ํด๋ฆญํ์ฌ ๋ซ๊ฒ ๋ ๊ฒฝ์ฐ, ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ด ์ผ์ด๋์ ๋งํ์ ๊น์ง ๋์์ ์ฌ๋ผ์ง๋ค.
๊ทธ๋์ ์ฒซ ๋ฒ์งธ๋ก ๋ํ๋๋ ๋ชจ๋ฌ์ ๋ซ์ ๋์ close
๋๋ ์ด๋ฒคํธ ์ชฝ์๋ค๊ฐ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ ์๋ ๋ฉ์๋๋ฅผ ์ฌ์ฉํด์ ๋ง์์ฃผ์๋ค.
event.stopPropagation()
์ ์ฌ์ฉํด์ฃผ๋ฉด ๋๋ค.
์ด๋ฒคํธ๊ฐ ์ฐ์ํ์ฌ ๋ฐ์ํ๋ ๋ฒ๋ธ ํ์์ ์๋ฏธํ๋ค.
์์ ์๋ฆฌ๋จผํธ์์ ์ด๋ฒคํธ ๋ฐ์ ์, ๋ถ๋ชจ ์๋ฆฌ๋จผํธ์ ๊ฐ์ ์ด๋ฒคํธ๊ฐ ์ค์ ๋์ด ์๋ค๋ฉด ํด๋น ์ด๋ฒคํธ์ ํ ๋น๋ ๊ธฐ๋ฅ๋ ํจ๊ป ์คํ๋๋ค.
๊ทธ๋์ ์ด ๊ฐ์ ํ์์ ๋ง๊ธฐ ์ํด์๋ e.stopPropagation()
์ ์ฌ์ฉํด์ ๋ง์์ฃผ๋ฉด ๋๋ค.
์ฐธ๊ณ : https://recoiljs.org/ko/
const fontSizeState = atom({
key: 'fontSizeState',
default: 14,
});
key : ๊ณ ์ ํ ํค๊ฐ ํ์
default : React ์ปดํฌ๋ํธ์ ์ํ์ฒ๋ผ ๊ธฐ๋ณธ๊ฐ๋ ๊ฐ์ง๋ค.
์ปดํฌ๋ํธ์์ atom์ ์ฝ๊ณ ์ฐ๋ ค๋ฉด useRecoilState
๋ผ๋ ํ
์ ์ฌ์ฉํ๋ค. React์ useState์ ๋น์ทํ์ง๋ง ์ํ๊ฐ ์ปดํฌ๋ํธ ๊ฐ์ ๊ณต์ ๋ ์ ์๋ค๋ ์ฐจ์ด๊ฐ ์๋ค.
์ฝ๊ธฐ ์ ์ฉ ์์ฑ์ ์ฌ์ฉํ๊ธฐ ์ํ ๊ฒ. ์ ์ฅํ ๋ฐ์ดํฐ๋ ๋ธ๋ผ์ฐ์ ์ธ์
๊ฐ ๊ณต์ ๋๋ค.
๋ก์ปฌ์คํ ๋ฆฌ์ง๋ ์ธ์
์คํ ๋ฆฌ์ง์ ๋น์ทํ์ง๋ง ๋ก์ปฌ์คํ ๋ฆฌ์ง์ ๋ฐ์ดํฐ๋ ๋ง๋ฃ๋์ง ์๊ณ , ์ธ์
์คํ ๋ฆฌ์ง์ ๋ฐ์ดํฐ๋ ํ์ด์ง ์ธ์
์ด ๋๋ ๋, ์ฆ ํ์ด์ง๋ฅผ ๋ซ์ ๋ ์ฌ๋ผ์ง๋ค.
myStorage = window.localStorage;
localStorage.setItem('ํค', '๊ฐ');
const cat = localStorage.getItem('ํค');
localStorage.removeItem('myCat');
localStorage.clear();
๋ก์ปฌ์คํ ๋ฆฌ์ง๋ ๋ฌธ์์ด๋ง ๋ฐ์์ค๊ธฐ ๋๋ฌธ์ number ๊ฐ์ ๋ฐ์์ค๊ณ ์ถ๋ค๋ฉด
Number(localStorage.getItem("counter");
์ด๋ฐ์์ผ๋ก ์ฌ์ฉํด์ค์ผํ๋ค.
ํ์
์ ์๋ ๋งจ ์์
์ฐ๊ด ๋ ๊ธฐ๋ฅ์ useState
์ useEffect
๋ ๋ฌถ์ด์ ๋๊ธฐ
๋ณต์กํ ์ฝ๋๋ hook์ผ๋ก ๋ถ๋ฆฌํ๊ธฐ
์๋ฐ์คํฌ๋ฆฝํธ๋ ๋์ ํ์
์ธ์ด์ด๊ธฐ ๋๋ฌธ์ ์ ์ ํ์
์ธ์ด์ธ ํ์
์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
ํ์
์ค๋ฅ๋ฅผ ์ฌ์ ์ ์๋ฐฉํ ์ ์๋ค.
ํจ์์ ๋ํ ํ์
์ ์ฃผ์์ผ๋ก ๋ฌ์๋๋ ๊ฒ์ด ์ข๋ค. (๋ฐํ๊ฐ์ ๋ํด์๋...)
ํ์
์คํฌ๋ฆฝํธ๊ฐ ์์ ๋์๋ prop-types๋ผ๋ ํจํค์ง๋ฅผ ์ค์นํด์ ์์ฑ๊ฐ ํ์
์ ์ ์
์กฐ๊ฑด๋ถ ๋ ๋๋ง์ด๋ ? ์ ํ์ ์ผ๋ก ๋ ๋๋งํ๋ ๊ฒ์ ๋งํ๋ค.
์ผํญ์ฐ์ฐ์
{isLogin ? (
<div>
<p>{name}๋ ์๋
ํ์ธ์</p>
</div>
) : null}
์ผํญ์ฐ์ฐ์ ์ฌ์ฉ์ ์ข์์
์ข ๋ ๊ฐ์ ๋ ์ฝ๋
{isLogin && (
<div>
<p>{name}๋ ์๋
ํ์ธ์</p>
</div>
}
const num = 'ab' && 0 && 2;
// result
const num = 'ab' && 2 && 3;
// result
๊ฑฐ์ง์ ๋ง๋๊ฑฐ๋ ๋ง์ง๋ง๊น์ง ํ๊ฐ๋ ๋ ๊ทธ ๊ฒ์ด ๋ต์ด๋๋ค.
๐ ์์ข์ ์
<div>
{cash && <p>{cash}์ ๋ณด์ ์ค</p>} // ----> 0์ผ ๊ฒฝ์ฐ
{memo && <p>{200 - memo.length}์ ์
๋ ฅ ๊ฐ๋ฅ</p>} // ----> '' ๋น ๋ฌธ์์ด์ผ ๊ฒฝ์ฐ
</div>
๐ ๊ฐ์ ๋ ์ฝ๋
์๋์ ๊ฐ์ด ๋ช ํํ๊ฒ ์ฒ๋ฆฌํด์ฃผ๊ธฐ
<div>
{cash !== null && <p>{cash}์ ๋ณด์ ์ค</p>} // ----> 0์ผ ๊ฒฝ์ฐ
{memo !== null && <p>{200 - memo.length}์ ์
๋ ฅ ๊ฐ๋ฅ</p>} // ----> '' ๋น ๋ฌธ์์ด์ผ ๊ฒฝ์ฐ
</div>
const v1 = 'ab' || 0;
// result
const v2 = '' || 0 | 3;
// result
์ฒ์์ผ๋ก ์ฐธ์ ๋ง๋ ๋ ๊ฐ์ด ๋๋ค.
const msg = null ?? 'hello';
const msg = undefined ?? 'hello';
null ์ด๋ undefined๊ฐ ์๋ ๊ฐ์ ์ถ๋ ฅํด์ค๋ค.
0
-0
NaN
' ' (๋น ๋ฌธ์์ด)
null
undefined
false
โ ๊ด์ฌ์ฌ์ ๋ถ๋ฆฌ๋ฅผ ํ์
๋น์ทํ ๊ธฐ๋ฅ์ ํ๋ ์ฝ๋๋ผ๋ฆฌ ๋ชจ์๋ค. (ex. UI๋ฅผ ์ฒ๋ฆฌํ๋ ์ฝ๋, ์๋ฒ API๋ฅผ ํธ์ถํ๋ ์ฝ๋, DB๋ฅผ ๊ด๋ฆฌํ๋ ์ฝ๋)
์ฐ๊ด๋ ์ปดํฌ๋ํธ๋ผ๋ฆฌ ํด๋๋ฅผ ๋ง๋ค์ด์ ๊ด๋ฆฌํ๋ค.
๋น์ฆ๋์ค ๋ก์ง์ด ์๋ค.
์ํฏ๊ฐ์ด ์๋ค.
useEffect(() => {
(...)
},[์์กด์ฑ ๋ฐฐ์ด])
์์กด์ฑ ๋ฐฐ์ด์ ๋ด๊ธด ๋ด์ฉ์ด ๋ณ๊ฒฝ ๋ ๊ฒฝ์ฐ ๋ถ์ ํจ๊ณผ ํจ์๊ฐ ์คํ๋จ
API ํธ์ถํ๊ณ ์ ํ ๋, useCallback
์์กด์ฑ ๋ฐฐ์ด์ ๊ฐ์ด ์์ด๋ ์๋ก์ด ๊ฐ ์์ฑํด์ฃผ๊ธฐ ์ํด์ ์ฌ์ฉ
function Profile({ userId }) {
const [user, setUser] = useState();
useEffect(() => {
(...)
},[user])
}
useCallback(() => {
ํจ์
}, [๋ณ๊ฒฝ๋ ํจ์])
if๋ฌธ์ ์ฌ์ฉํด์ ๋ถ๊ธฐ์ฒ๋ฆฌํ์ฌ api ํธ์ถ ์คํ ์์ ์ ๊ด๋ฆฌํ๋ค.
useEffect(async () => {
const data = await fetchUser(A,B);
},[])
๋ถ์ํจ๊ณผ ํจ์์ ๋ฐํ๊ฐ์ ํญ์ ํจ์ ํ์
์ด์ด์ผ ํ๋ค.
async await ํจ์๋ promise ๊ฐ์ฒด๋ฅผ ๋ฐํ.
useEffect(() => {
async function test () {
const data = await fetchUser(A,B);
}
},[])
async function test () {
const data = await fetchUser(A,B);
}
useEffect(() => {
test()
},[])
๋ฆฌ์กํธ์์ ์ต์ด ๋ ๋๋ง ํ, ๋ฐ์ดํฐ ๋ณ๊ฒฝ ์ ๋ ๋๋ง์ ํ๋๋ฐ ์ด์ ๊ฐ์ ๋จ๊ณ๋ฅผ ๊ฑฐ์น๋ค.
์ด์ ๋ ๋๋ง ๊ฒฐ๊ณผ๋ฅผ ์ฌ์ฌ์ฉํ ์ง ํ๋จํ๋ค.
์ปดํฌ๋ํธ ํจ์๋ฅผ ํธ์ถํ๋ค.
๊ฐ์ ๋๋ผ๋ฆฌ ๋น๊ตํด์ ๋ณ๊ฒฝ๋ ๋ถ๋ถ๋ง ์ค์ ๋์ ๋ฐ์ํ๋ค.
์ปดํฌ๋ํธ์ ๋ฆฌ๋ ๋๋ง์ ๋ง์์ค๋ค.
function MyComponent(view){
// ...
}
React.memo(MyComponent, view);
์์ฑ๊ฐ๊ณผ ๋น๊ตํด์ ๊ฐ๋ค๋ฉด ์ฐธ์ ๋ฐํํ์ฌ ์ด์ ์ ๊ฐ์ ์ฌ์ฌ์ฉ์ ํ๋ค.
์์ฑ๊ฐ๊ณผ ๋น๊ตํ์ฌ ๋ค๋ฅด๋ค๋ฉด ๊ฑฐ์ง์ ๋ฐํํ์ฌ ์๋ก์ด ๊ฐ์ ๋ค์ ๋ฆฌ๋ ๋๋ง ํด์ค๋ค.
useMemo : ๊ฐ์ ๋ฉ๋ชจ์ ์ด์
useCallback : ํจ์๋ฅผ ๋ฉ๋ชจ์ ์ด์
useRef๋ก ์๋ฆฌ๋จผํธ ์ก์ ๊ฒฝ์ฐ์๋
$elSlide
์ด๋ ๊ฒ ๋ฌ๋ฌํ์๋ el๋ก ๋ค์ด๋ฐ ์ง์ ํ๊ธฐ
์๋ฆฌ๋จผํธ ํฌ์ปค์ค ๋ฟ๋ง ์๋ ๊ทธ๋ฅ ๋ณ์ ์ ์ฅํ๊ธฐ ์ํด์๋
const variable = useRef<{
// ์ฌ๋ผ์ด๋ ์ ๋๋ฉ์ด์
๋ฉ์ถ๊ธฐ ์ํ ๊ณ ์ id๊ฐ
slideStop: number,
// ์ฌ๋ผ์ด๋ ์ ์ฒด๋๋น - ์ ์ ๋๋ฐ์ด์ค ๋๋น = slide ๊ฐ์ฅ ๋ X ์ง์
slideWidth: number,
// ์ฌ๋ผ์ด๋ X๊ฐ ์์น
slideCurrent: number,
// ๋ฉ์ธ Top10 ์ด๋?
bTopTenMain: boolean
}>({
slideStop: 0,
slideWidth: 0,
slideCurrent: 1,
bTopTenMain: type === TopTenType.Main
});
์ด๋ ๊ฒ ๋ฌถ์ด์ ์ฌ์ฉํ๊ธฐ.
boolearn ๊ฐ์ด๋ฉด b๋ก ์์ํ๋ ๋ค์ด๋ฐ์ผ๋ก ์ง๊ธฐ
์ ๋งํ๋ฉด const ์ฌ์ฉํ๊ธฐ. ๊ทธ๋ฆฌ๊ณ ํ์
์ง์ ๊ผญ ํ๊ธฐ
์ฃผ์์ ๋ํ
์ผํ๊ฒ ์ ์์๋ก ์ข๋ค.
if() ์ฐ๊ธฐ
ํ์ ์ ์ํ ๋ any๋ ์ฐ์ง๋ง๊ธฐ. ํ์ง๋ง ๋ชจ๋ฌ์ผ ๊ฒฝ์ฐ๋ ์ด์ฉ ์ ์์.
์์ ์๋ฆฟ์๋ก ๋ฐ์ฌ๋ฆผ๋ ์ซ์๋ฅผ ๋ฌธ์์ด ํ์ ์ผ๋ก ๋ฐํํ๋ค.
(123.678).toFixed();
// 124
(123.678).toFixed(1);
// 123.7
๊ฐ์ฅ ๊ฐ๊น์ด ์ ์๋ก ๋ฐ์ฌ๋ฆผ๋ ์ซ์๋ฅผ ๋ฐํํฉ๋๋ค.
Math.round(123.456);
// 123
Math.round(123.678);
// 124
Math.round(123.9191);
// 124
๊ฐ์ฅ ๊ฐ๊น์ด ์ ์๋ก ๋ด๋ฆผ๋ ์ซ์๋ฅผ ๋ฐํ
Math.floor(123.456);
// 123
Math.floor(123.678);
// 123
๊ฐ์ฅ ๊ฐ๊น์ด ์ ์๋ก ์ฌ๋ฆผ๋ ์ซ์๋ฅผ ๋ฐํ
Math.ceil(123.456);
// 124
Math.ceil(123.678);
// 124
์ ๋ฌ๋ ๊ฐ๋งํผ ํํํ ์์ ๊ธธ์ด๋ฅผ ์ ํํ๋ฉฐ, ์ซ์๋ฅผ ๋ฌธ์์ด ํ์ ์ผ๋ก ๋ฐํ
์ฐธ๊ณ
https://developer-talk.tistory.com/304
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Math/random
๋ก์ปฌ ์คํ ๋ฆฌ์ง์ ์ ์ฅํ๊ณ ํ ๋ง ์ฌ๋ถ์ ๋ฐ๋ผ ๋คํฌ๋ชจ๋ ๋๋ ๋ผ์ดํธ๋ชจ๋๋ก ์ค์ ํด์ฃผ์๋ค.
<Helmet>
<html data-theme={mobx ์ํ๊ด๋ฆฌ์์ ์ ์ฅํ ํ
๋ง์ ๊ฐ์ ๋ถ๋ฌ์ด} />;
</Helmet>
JSX ์์์๋ ์ด๋ผ๋ react-helmet ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ๋คํฌ๋ชจ๋ ํ ๋ง์ ์ค์ ๋ ์ํ๊ฐ์ ๋ถ๋ฌ์จ๋ค.
4๊ฐ์ง ๋ฉ์๋๊ฐ ์๋ค (setItem, getItem, clear, remove)
JSON.stringity
๋ฅผ ์ฌ์ฉํ์ฌ string
ํ์
์ผ๋ก ๋ณํ์์ผ์ฃผ์ด์ผ ํ๋ค.๊ทธ๋ฆฌ๊ณ ์กฐํ๋ฅผ ํ ๋๋ ๊ฐ์ฒดํ์ผ๋ก ๋ถ๋ฌ ์์ผํ๊ธฐ ๋๋ฌธ์ string
ํ ๋ ํ์
์ ๋ค์ JSON.parse
๋ก object
์์ผ๋ก ๋ณํํ์ฌ ์กฐํ(get)ํ๋ค.
// JSON ์ผ๋ก ๋ก์ปฌ ์คํ ๋ฆฌ์ง ๋ฐ์ดํฐ ์์ฑ
localStorage.setItem('key', JSON.stringity({ a: value }));
// JSON์ผ๋ก ์คํ ๋ฆฌ์ง ๋ฐ์ดํฐ ์กฐํ
JSON.parse(localStorage.getItem('key'));
// key์ ํด๋นํ๋ ์คํ ๋ฆฌ์ง๋ง ์ญ์
localStorage.remove('key')
// ๋ชจ๋ ์คํ ๋ฆฌ์ง ์ญ์
localStorage.clear('key')
$ git config --global user.name "Your Name"
$ git config --global user.email [email protected]
// git ์ด๋ฉ์ผ ๋ฑ๋ฑ ํ์ธ
git config --list
PC์ MO๋ฒ์ ๊ฐ์ด ์์
ํ๋ ๋ฐ์ํ ์น ํ๋ก์ ํธ ์์
์ค์ ์ผ์ด๋ ๊ฒฝ์ฐ๋ค.
localhost:3000์์ pc๋ก ๋ดค์ ๋๋ ์ ๋ณด์ด๋๋ฐ, ๊ฐ๋ฐ์๋๊ตฌ์์ ๋ชจ๋ฐ์ผ๋ก ๋ณ๊ฒฝ ํ ์๋ก๊ณ ์นจํ๋ฉด
๋ชจ๋ฐ์ผ ๋ฒ์ ์ผ๋ก ๋ง์ถคํ ๋ผ์ ์ ๋์์ผํ๋๋ฐ ์ธํฐ๋ท ์ฐ๊ฒฐ์ด ์คํจ๋๋ค๋ ํฌ๋กฌ ๋ค์ด๋
ธ์ ํจ๊ป ์๋ฌ ๋ฌธ๊ตฌ๊ฐ ๋ณ๋ค.
์ด๋ฐ ์ํฉ์์ ํฌ๋กฌ ๋๋ฒ๊ทธ ๋จนํต์ด๋ผ๊ณ ํ๋ค.
๋ ๋ค๋ฅธ ์๋ก๋ console.log('text')๋ผ๋ ์ฝ๋๊ฐ ์์ด๋ ์ฝ์์ฐฝ์ ๋ฉ์์ง๊ฐ ๋จ์ง ์๋ ๊ฒฝ์ฐ๋ฅผ ๋ณผ ์๊ฐ ์๋ค.
๋ฒํผ์ ์ด๋ฒคํธ๋ฅผ ์ค๋ ์ด๋ฒคํธ๊ฐ ์คํ์ด ๋์ง ์์ ๊ฒฝ์ฐ๋ ๋ง์ฐฌ๊ฐ์ง๋ค.
์ค์ ๋ค์ ์์๋ณต๊ตฌ ํด์ฃผ๋ฉด ๋๋ค.
์ด์๊ฐ์ด ํฑ๋๋ฐํด(=setting)๋ฅผ ํด๋ฆญํ๋ฉด ๋๋ฒ๊ทธ ๋ชจ๋ ์ค์ ์ฐฝ์ผ๋ก ์ ํ๋๋ค.
Restore defaults and reload ๋ผ๋ ๋ฒํผ์ ํด๋ฆญํ๋ฉด ๋๋ค.
๋ฌด์จ ์๋ฏธ๋๋ฉด ๋ชจ๋ ํฌ๋กฌ ๋๋ฒ๊ทธ ์ค์ ๋ค์ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๋๋๋ฆฌ๋ฉด ๋๋ค๋ ์๋ฏธ๋ค. (= ํฌ๋กฌ ๋๋ฒ๊ทธ ์ค์ ์ด๊ธฐํ)
์ด๋ ๊ฒ ํ๊ณ ๋๋ ํฌ๋กฌ ๋๋ฒ๊ทธ ๋จนํต, ๋ฉ์ถค ํ์์ ์ฌ๋ผ์ง๊ณ ์ ๋๋ก ์ ์๋ ๋๋๊ฒ์ ๋ณผ ์ ์์๋ค.
$brew tap theeternalsw0rd/telnet
$brew install telnet
$telnet host_ip port
const arrDealList = () => {
const list = []; // ๐ ๋ด์๋ผ ๋ณ์
// ๐ ์ค์ ๋ฐฐ์ด ๋ณ์ ์ ์ธํด์ผํจ _ ๋ฐฐ์ด์ ๊ธธ์ด๋งํผ ๋ฐ๋ณต๋ฌธ์ ๋๋ฆฌ์.
for (let i = 0; i < domeRankList.length; i++) {
list.push(<DealList rankName={domeRankList[i]} listName={coinList[i]} key={i} />);
}
// ๐ ๋ฆฌํด !
return list;
};
return (
<div className="domestic__coinlist">
<Division coinName={coinList[0]} />
{arrDealList()} // ๐ ๋ฆฌํด ๋ ํจ์ ์ ์ธํ์ฌ list ๋ฟ๋ ค์ฃผ๊ธฐ
(...)
</div>
)
const url = encodeURI(window.location.href);
// Facebook
const shareFacebook = () => {
window.open("http://www.facebook.com/sharer/sharer.php?u=" + url);
}
// Twitter
const shareTwitter = () => {
window.open("https://twitter.com/intent/tweet?url=" + url)
}
// ๋ผ์ธ
// ํ
๋ ๊ทธ๋จ
const shareTelegram = () => {
window.open("https://telegram.me/share/url?url=" + url);
}
(1) ์นด์นด์ค ๊ฐ๋ฐ์ ๋ฑ๋ก ๋ฐ ํค ๋ฐ๊ธ
๋จผ์ , ์นด์นด์ค ๊ฐ๋ฐ์ ํ์ด์ง์ ์ ์ํ์ฌ ๊ฐ๋ฐ์ ๊ณ์ ์ผ๋ก ๊ฐ์
ํ๋ค. (๋งํฌ : developers.kakao.com/)
์ฐธ๊ณ ์๋ฃ : https://abangpa1ace.tistory.com/255
์์๋ณต์ฌ
const obj1 = { a : b, b : 2 };
const obj2 = obj1;
console.log( obj1 === obj2 ); // true
console.log(obj1); // {a: 1, b: 2}
console.log(obj2); // {a: 1, b: 2}
์ด ์์์ฒ๋ผ ๊ฐ์ฒด๋ฅผ ์ง์ ๋์ ํ๋ ๊ฒฝ์ฐ ์ฐธ์กฐ์ ์ํ ํ ๋น์ด ์ด๋ฃจ์ด์ง๋ฏ๋ก ๋์ ๊ฐ์ ๋ฐ์ดํฐ (์ฃผ์)๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ์ด๊ฒ์ ์์ ๋ณต์ฌ๋ผ๊ณ ํ๋ค.
๊น์๋ณต์ฌ
const dog = {a: 1, b: 2};
const cat = {...dog};
cat.a = 100;
console.log(dog === cat) // false
console.log(cat.a) // 1
...(spread) ์ฐ์ฐ์๋ฅผ ํตํด ๋ธ๋ก ์์ dog์ ์์ฑ์ ๋ณต์ฌํ๋ฉฐ cat์ ํ ๋นํ์๋ค. ์ด์ dog์ cat์ ๋ค๋ฅธ ์ฃผ์๋ฅผ ๊ฐ๊ฒ ๋์๋ค. ๋ฉ๋ชจ๋ฆฌ ์ฐธ์กฐ๊ฐ ๋ค๋ฅธ ๊ฒ.
src/react-app-env.d.ts ํ์ผ์๋ค๊ฐ
interface Window {
Kakao : any;
}
์ด๋ฐ์์ผ๋ก ์ ์ธํด์ ์ฌ์ฉํ ๋๋
const kakao = window.Kakao;
์ด๋ ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ public/index.html
ํ์ผ์
<script src="https://developers.kakao.com/sdk/js/kakao.js"></script>
์ด๋ ๊ฒ ์๋จ์๋ค ์ ์ธํด์ฃผ์ด์ผ ์นด์นด์ค ์์
๊ณต์ ํ๊ธฐ ๊ฐ๋ฅ.
๐๐ปโโ๏ธ ๊ทธ๋ฆฌ๊ณ ๋ฐ๋์ ํค๊ฐ์ด ์์ด์ผํ๋ค.
ํค๊ฐ์ ์นด์นด์ค developer ์ ๊ฐ์ ์ฑ ๋ฑ๋กํ๋ฉด ํค ๊ฐ ์ป์ด์ค๊ธฐ ๊ฐ๋ฅํ๋ค.
JavaScript ํค : f661d4bba439f1455cefe8dfdfaa2b4513ee04
ํค๊ฐ์ ์ด๋ ๊ฒ ์๊ฒจ๋จน์.
์ด๊ฑธ env ํ๊ฒฝ ํ์ผ์๋ค๊ฐ ์ ์ธํด์ ๊ฐ๋ค ์ฐ๋ฉด๋๋ค.
REACT_APP_KAKAO_KEY=f661d4bba439f1aaaaa455cefe82b4513ee04
์๋ฐ์ ! ๊ฐ๋ค ์ธ ๋๋ kakao.init(process.env.REACT_APP_KAKAO_KEY
์ด๋ ๊ฒ ์ฐ๋ฉด ๋๋ค.
{
item.title!.length<25
? <span className={`${styles.title} ${styles.shorts}`}>{item.title}</span>
: <span className={styles.title}>{item.title}</span>
}
์ด๋ ๊ฒ ํ ์คํธ ๊ธธ์ด๋ก ์ธก์ ํด์ ์คํ์ผ์ ์ฃผ๋ ๋ฐฉ๋ฒ๋ ์๋ค.
.title {
๐ display: inline-block;
๐ white-space: nowrap;
๐ overflow: hidden;
๐ text-overflow: ellipsis;
๐ width: 58% !important;
&.shorts {
width: 55% !important;
text-overflow: clip;
}
}
์ด๋ ๊ฒ width ๊ฐ์ ์ฃผ๊ณ ... ์ฒ๋ฆฌํ๊ธฐ ์ํด์๋ ๐ ๋ก ํ๊ธฐํด๋
[mock.js]
server.get('/api/v1/cms/notice/detail/:boardID')`
import { useParams } from 'react-router';
// ์์ธ ํ์ด์ง ์ฝํ
์ธ ๋ด์ฉ ๋ถ๋ฌ์ค๊ธฐ ์ํด์ useParams๋ฅผ ์ฌ์ฉํ๋ค.
// useParams๋ react-router์์ ์ ๊ณตํด์ฃผ๋ ๋ฉ์๋๋ค.
const path: BoradProps = useParams();
const [notice, setNotice] = useState<string>('');
useEffect(() => {
if (path.boardID) {
try {
const getNotice = async () => {
const data = await ๋ถ๋ฌ์ค๋๋ฉ์๋.get(`/api/v1/cms/notice/detail/:${boardID}`);
setNotice(data.data);
}
// ๐ api ๋ถ๋ฌ์ค๊ธฐ
getNotice();
} catch (error) {
console.log('error---->', error);
}
}
},[path]);
import { Route } from 'react-router';
<Route exact path={'menu/board-view/:boardID'} component={BoardView} />
๋ผ์ฐํธ ํ ์ฃผ์์ ํ๋ผ๋ฏธํฐ๊ฐ๋ boardID
์ด ๋์ผํ ๊ฐ์ผ๋ก ํด์ฃผ์ด์ผ ๋ฐ์์ฌ ์ ์๋ค.
๋ธ๋ผ์ฐ์ ์ ๋ํ ์๋ณ ์ฝ๋๋ก ์ฌ๋์ผ๋ก ์๊ฐํ๋ฉด "์ฃผ๋ฏผ ๋ฑ๋ก์ฆ" ๊ณผ ๊ฐ์ ๊ฒ ์๋ณ๋๋ ๊ฒ์ ์ปดํจํฐ(๋จ๋ง๊ธฐ)์ ๋ํ OS ์ ๋ณด, ๋ธ๋ผ์ฐ์ ๋ฒ์ , ๋ ์ด์์ ์์ง ์ข ๋ฅ ๋ฑ ๋ด์์ ํญ์ ์๋ฒ์ ํต์ ํ ๋ ์ ์์ ์ ๋ณด๋ฅผ ๋ปํ๋ค.
์ฝ๋์์
var userAgent = window.navigator.userAgent;
var isChrome = userAgent.indexOf('Chrome');
var isChromeMobile = userAgent.indexOf('CriOS');
var isSamsungBrowser = userAgent.indexOf('SamsungBrowser');
var isWindows = userAgent.indexOf('Windows NT');
var isEdge = userAgent.indexOf('Edge');
var isIE = userAgent.indexOf('Trident');
์ด๋ฐ ๋๋์ผ๋ก ์ฌ์ฉํ๋ฉด ๋๊ณ , IF๋ฌธ์ผ๋ก ์์ ํ ๋๋
var isChrome = userAgent.indexOf('Chrome');
// ํฌ๋กฌ์ผ๊ฒฝ์ฐ
if(isChrome > -1) {
}
// ํฌ๋กฌ์ด ์๋ ๊ฒฝ์ฐ
if(isChrome === -1) {
}
์ด๋ฐ์์ผ๋ก ์ฌ์ฉํ๋ฉด ๋๋ค. if๋ฌธ์ผ๋ก ์ ์ ํ๊ฒ ์ปค์คํ ํด์ ์ฌ์ฉํ๋ฉด๋จ.
Navigator ์ธํฐํ์ด์ค๋ ์ฌ์ฉ์ ์์ด์ ํธ์ ์ํ์ ์ ์ ์ ๋ณด๋ฅผ ๋ํ๋ด๋ฉฐ, ์คํฌ๋ฆฝํธ๋ก ํด๋น ์ ๋ณด๋ฅผ ์ง์ํ ๋์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํน์ ํ๋์ ๋ฑ๋กํ ๋ ์ฌ์ฉํฉ๋๋ค.
Navigator.userAgent.indexOf('๋ธ๋ผ์ฐ์ ๋ช
')
if(navigator.userAgent.indexOf('SamsungBrowser') > -1){
}
๐ ์ฐธ๊ณ ์๋ฃ
codepen ์์
https://codepen.io/zineeworld/pen/oJyZOq
[JS] User Agent ๋ธ๋ผ์ฐ์ ์ ๋ณด ์ป๊ธฐ (ํฌ๋กฌ์ธ์ง ์๋์ง ์ฒดํฌํ๊ธฐ)
https://zinee-world.tistory.com/512
https://developer.mozilla.org/ko/docs/Web/API/Window/navigator#%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80_%ED%98%B8%ED%99%98%EC%84%B1
Window.navigator MDN
https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EC%9B%B9%ED%8E%98%EC%9D%B4%EC%A7%80%EC%97%90-%EC%A0%91%EC%86%8D%ED%95%98%EB%8A%94-%EA%B8%B0%EA%B8%B0%EB%AA%A8%EB%B0%94%EC%9D%BC%ED%83%9C%EB%B8%94%EB%A6%BFPC-%EA%B5%AC%EB%B6%84%ED%95%98%EA%B8%B0
์ด๊ธฐ ๋ ๋๋ง ์์ ์ฌ์ฉํ๋ ๊ฐ์ด๋ค.
์ํ์ ๋ณํ๋ฅผ ์ค๋ค.
const [color, setColor] = useState<string>('red');
const [color, setColor] = useState<string>('red');
const handleChange = () => {
setColor('pink');
}
return (
<>
<button onClick={handleChange}>
์ปฌ๋ฌ ๋ณ๊ฒฝ
</button>
<div xss=removed>์ปฌ๋ฌ๋ณ๊ฒฝ ๋ฒํผ์ ํด๋ฆญํ๋ฉด ์๊น์ด ๋ณํด์</div>
</>
)
๋ธ๋ผ์ฐ์ ๊ฐ ํ๋ฉด์ ๊ทธ๋ฆฌ๊ณ ๋ ๋ค์ ๋ ๋๋ง์ด ๋๋ค.
๋น๋๊ธฐ๋ก ํธ์ถํด์ค๋ค.
useEffect(() => {
๊ฐ์ ๋์์ด ๋ณํ๋ฉด ๋์ ํ ์ฝ๋ฐฑ
return () => {
}
},[๊ฐ์๋์])
// ์ฒซ ๋ ๋๋ง ํ ์คํ๋๋ค
useEffect(() => {
์ฝ๋ฐฑ
},[])
// ํ์ด์ง์์ ๋ ๋ ๋ ์คํ
useEffect(() => {
return ()=> {
console.log('bye~')
}
},[])
// ๊ฐ์๋์์ด ๋ณํ๋ฉด ๋์๋๋ ์ฝ๋ฐฑํจ์
useEffect(() => {
์ฝ๋ฐฑ
},[๊ฐ์ ๋์])
useEffect(() => {
consoloe.log(๊ฐ์ ๋์)
return ()=> {
console.log('bye~')
}
},[๊ฐ์ ๋์])
๋๊ธฐ๋ก ํธ์ถํด์ค๋ค.
๋ธ๋ผ์ฐ์ ๊ฐ ํ๋ฉด์ ๊ทธ๋ฆฌ๊ธฐ๋ ์ ์ ์คํํด์ค๋ค.
useLayoutEffect(() => {
return () => {
}
},[])
๋ง์ฝ ์ด useLayoutEffect ์์ ์ฐ์ฐ๋์ด ๋ง์ ์ฝ๋๊ฐ ๋ค์ด๊ฐ๊ฒ ๋๋ค๋ฉด ์ฌ์ฉ์์ ํ๋ฉด์ ๋ฒ๋ฒ
์์ ๋๋ ์๊ฐ ์๋ค.
๊ทธ๋์ ๋ธ๋ผ์ฐ์ ๊ฐ ํ๋ฉด์ ๊ทธ๋ฆฌ๊ณ ๋ ๋ค์ ๋ ๋๋ง์ ํด์ฃผ๋ useEffect๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
๋ ๋๋ง ์ฑ๋ฅ์ ์ํด ์ฌ์ฉ
useCallback(() => {
์ฝ๋ฐฑํจ์
},[์์กด์ฑ])
// ๋งค๋ฒ ์๋กญ๊ฒ ์์ฑ๋๋ค
const hyunju = () => { }
// ๋งค๋ฒ ์๋กญ๊ฒ ์์ฑ๋์ง ์๋๋ค.
const hyunju = callback(() => {
},[])
// a๊ฐ์ด ๋ณํ์ง ์๋ ์ด์ ๋งค๋ฒ ์๋กญ๊ฒ ์์ฑ๋์ง ์๋๋ค.
const hyunju = callback(() => {
},[a])
DOM ์์์ ์ง์ ์ ๊ทผํ๊ธฐ ์ํด ๋ ์์์ ํฌ์ปค์ค๋ฅผ ์ค ๋ ์ฌ์ฉ
๋ ๋๋ง๊ณผ ๋ฌด๊ดํ ๊ฐ์ ์ ์ฅํ๋ค.
์ด๋ค ๊ฐ์ด๋ ์ ์ฅํ ์ ์๋ค.
useState ์ฒ๋ผ ์ด๊ธฐ๊ฐ๋ ๋ฃ์ ์ ์๋ค.
const TextInput = () => {
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
inputRef.current.focus();
}, [])
return (
<>
<input type="text" ref={inputRef} />
<button>์ ์ฅ</button>
</>
)
}
๋ ๋๋ง๋ DOM๋
ธ๋์ dangerouslySetInnerHTMLํ๊ทธ๋ฅผ ์ฌ์ฉํ์ฌ
์ง์ ์ ์ผ๋ก HTML์ ์ฝ์
ํ ์ ์์ต๋๋ค.
์ด๋ฌํ ๋งํฌ๋ค์ ๋ฏธ๋ฆฌ ๊ฒ์ฌํ์ฌ ๋ฐฉ์งํ ํ์๊ฐ ์์ต๋๋ค.
dangerouslySetInnerHTML prop์ ์ง์ ๋๊ธฐ ์ ์ ๋ชจ๋ ๊ฐ๋ค์
dompurify์ ๊ฐ์ sanitization library๋ฅผ ์ฌ์ฉํ์ฌ sanitizeํด์ฃผ์ด์ผ ํฉ๋๋ค.
import purify from "dompurify";
(...)
<div dangerouslySetInnerHTML={{ __html:purify.sanitize(data) }} />
๋ฐ๋ผ์ ์ปจํ ์ธ ๋ฅผ DOM nodes์ ์ง์ ์ ์ผ๋ก ๋ฃ์ผ๋ ค DOM์ ์ ๊ทผํด์๋ ์๋ฉ๋๋ค.
dangerouslySetInnerHTML ํ๊ทธ๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ dompurify๋ฅผ ์ฌ์ฉํ์ฌ HTML์ด ์ฝ์ ๋๊ธฐ ์ sanitizeํด์ฃผ์ด์ผ ํฉ๋๋ค.
(1) ์ต๊ทผ ๊ฒ์ํ ํค์๋ โ ํค์๋๋ฅผ ๊ฒ์ ํ ํด๋น ์์ดํ ์ ํด๋ฆญ ํ์ ๋ ์ด๋ฒคํธ ๊ฑธ๊ธฐ
์ค๋ณต๋ ๊ฒ์์ด๊ฐ ์์ ๊ฒฝ์ฐ ์๋ ๊ธฐ๋ก์ ์ง์์ง๊ณ ์ต์ ๊ธฐ๋ก์ ์์ผ๋ก ๋น๊ธด๋ค.
๊ฒ์ ํค์๋ ๋ด์ญ 10๊ฐ ๊น์ง๋ง ๋ณด์ฌ์ง๋๋ก ! 11๊ฐ ์งธ๋ถํฐ ์ฌ๋ผ์ง๊ณ ์๋กญ๊ฒ ์ถ๊ฐ๋๋ค.
์ฌ์ฉํ ๋ฉ์๋ filter
, _(lodash)
, unshift
, pop
, localstorage
_ lodash
if (_.filter(๊ฒ์๋ ๋ฆฌ์คํธ, ๊ฒ์ํ ํค์๋).length > 0) {
...
}
๊ฒ์๋ ๋ฆฌ์คํธ์ ๋ด๊ฐ ๊ฒ์ํ ํค์๋ ๊ฐ์ด ์๋ค๋ฉด 1 ์๋ค๋ฉด -1์ด๋ค. (indexOf)
๊ฐ์ ์ญํ ์ ํด์ค๋ค.
๊ทธ๋ฌ๋ฏ๋ก ์์ ๊ฒฝ์ฐ 0๋ณด๋ค ํดํ ๋ ๋ถ๋ฑํธ๋ฅผ ์ฌ์ฉํ์ฌ ์กฐ๊ฑด์ ๊ฑธ์ด์ฃผ๊ณ ๋ธ๋ก์์ ์๋ก์ด ๋ฐฐ์ด์ ๋ง๋ค์ด์ง ์ ์๋๋ก ์ฝ๋ ๋ก์ง์ ์์ฑํ๋ค.
keywordList = keywordList.filter((item) => {
// item์ ๊ฒ์๋ช
๊ณผ ๋ด๊ฐ ํด๋ฆญํ ๊ฒ์ ๊ฒฐ๊ณผ ์์ดํ
์ด ๋ค๋ฅธ ์ ๋ค์ ์์ผ๋ก ๋ณด๋ด๊ธฐ
return item.coin !== newCoinMarket.coin || item.market !== newCoinMarket.market;
});
// ์๋ก์ด ๋ฐฐ์ด์ ๋ด๊ฐ ํด๋ฆญํ ๊ฐ์ฒด๋ฅผ ์๋ก ์ถ๊ฐํด์ฃผ์
keywordList.unshift(newCoinMarket);
}
filter
์ map
์ ์๋ก์ด ๋ฐฐ์ด์ ๋ง๋ค์ด์ฃผ๋ ES6 ๋ฌธ๋ฒ์ด๋ค. ๊ทธ๋์ ์ ์ญ๋ณ์๋ก ์ ์ธ๋ keywordList
์ ์๋ก์ด ๋ฐฐ์ด๊ฐ์ ๋ง๋ค์ด์ฃผ๋๋ฐ, ์ด์ฒ๋ผ ๋ฐํ๋ ๊ฐ์ด ํ์ฌ ์๋ item์ coin๊ณผ ๋ด๊ฐ ์ฐพ๊ณ ์ ํ coin์ด ์ผ์นํ์ง ์์ผ๋ฉด์ ~ ( || (OR) ์ฐ์ฐ์) market ๋ํ ์ผ์นํ์ง ์๋ ๋ค๋ฅธ ์ ๋ค์ ์์ผ๋ก ๋ณด๋ด์ค๋ค. (unShift)
์ด๋ ๊ฒ filter๋ก ํ์ฌ๊ธ ์๋ก์ด ๋ฐฐ์ด์ ๋ง๋ค์ด์ค๋ค.
๊ทธ๋ฆฌ๊ณ ์๋ก์ด ๋ฐฐ์ด์ด ๋ง๋ค์ด์ง keywordList ๋ฐฐ์ด์ ๋ด๊ฐ ํด๋ฆญํ ์์ดํ ์ ์๋ก ์ถ๊ฐํด์ค์ผ๋ก์ ์ต๊ทผ ๊ฒ์ํ ๊ฒ์๋ช ์ ์ค๋ณต๋ ์ ๋ค์ ํ ๋ฒ์ ์ทจํฉ๋ผ์ ์ต์ ๊ธฐ๋ก ์์๋ก ์ฎ๊ฒจ์ง๊ฒ ๋๊ณ ์ค๋ณต๋ ๊ฐ๋ค์ ์์ผ๋ก ๊ฐ๋ฉด์ new ๋ฐฐ์ด๊ฐ์ด ์๊ธฐ๋๋ก ํ๋ค.
ํ์ดํํจ์์์ ๊ฐ์ ๋ฐํํ ๋, function ํจ์์๋ ๋ฌ๋ฆฌ
const sum = (num1, num2) => num1 + num2
์ด๋ ๊ฒ ๋ธ๋ก ์์ด ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ค.
ํ์ง๋ง ๋ธ๋ก์์์๋ retrun์ ์ฌ์ฉํด์ผํ๋ค.
const sum = (num1, num2) => {
return num1 + num2;
}
unShift๋ก ๋ฆฌ์คํธ์ ์์ดํ
์ถ๊ฐํ๊ธฐ
๊ทธ๋ ๊ฒ ์ต๊ทผ ๊ฒ์ํ ๊ฐ์์์ฐ ๊ธฐ๋ฅ ๊ตฌํ ์๋ฃ
๊ทธ๋ ๊ฒ ํ๊ธฐ ์ํด์ ๋ค์ํ ๋ก์ง์ผ๋ก ์กฐ๊ฑด๋ฌธ์ ๋ง๋ค์ด์ ์์
ํด๋ดค์ผ๋, ์๊ฐ ์ง์ฐ์ผ๋ก ์ด๋ฏธ ๋ง๋ค์ด์ง ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๋ค.
๊ฒ์ํ ๋ ํนํ ๊ฐ์ฅ ์ด๋ ค์ ๋ ๊ฒ์ด ๋ฌด์ ์ด๋๋ฉด ํ๊ธ ๊ฒ์ํ ๋๋ ์ด์ฑ, ์ข
์ฑ, ์ค์ฑ ๊ทธ๋ฆฌ๊ณ ์์๊ณผ ๋ชจ์์ด ์๊ณ '์ป'์ ์
๋ ฅํด๋ ์ด๋๋ฆฌ์์ด๋ผ๋ ๊ฒฐ๊ณผ๋ฌผ์ด ๋์ค๊ธฐ ์ํด์๋ ๋๋ฒ์๋ ๊ณ ๋ คํด์ ํด์ผํ๋ค. ๊ทผ๋ฐ ๊ทธ๊ฒ์ ์ ๋ถ ์ฒ๋ฆฌํด์ฃผ๋ ํ๊ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์์๋ค. โ hangul.js
์ฐธ๊ณ ํ๊ธฐ
hangul.js์์ ์ ๊ณตํด์ฃผ๋ ๋ฉ์๋ ๊ธฐ๋ฅ๋ ๋ค์ํ๋ค !
ํ์ฌ ๋ด๊ฐ ์
๋ ฅํ ํค์๋์ ๋ํด์ ํ์ด๋ผ์ดํฐ ํจ๊ณผ๋ฅผ ์ฃผ๊ธฐ ์ํด์๋ indexOf, split, splice, join
๋ฑ๋ฑ ์ฌ๋ฌ ๋ฉ์๋๋ค์ ์ ํ์ฉํด์ผ๋๋๋ฐ
ํ๋ค๊ฐ ๊ตฌ์กฐ์์ฒญํ๋ค. ์ํผ ๋ฐฐ์ด ์ชผ๊ฐ๊ณ ๋ถํ๊ณ ํ๋ ๋ฅ๋ ฅ๋ ๋ถ์กฑํ ๊ฒ ๊ฐ๋ค. ๋ฐ๋ก ์ฐ์ตํด๋ณด์ !
mobx๋ก get ํ ๋ฐ์ดํฐ๋ค์ ์กฐํ ํ ๋,
์ฝ์ ๋ก๊ทธ๋ก ์ฐ์ด๋ณด๋ Proxy {0: ... }
ํํ๋ก ์ถ๋ ฅ์ด ๋ ๊ฒฝ์ฐ์ ํด๊ฒฐํ ๋ฐฉ๋ฒ์ด๋ค.
toJS(๋ฐ์ดํฐ๊ฐ);
์ด๋ ๊ฒ ํธ์ถํ๋ฉด Proxy๊ฐ ๋ฒ๊ฒจ์ง๊ณ ๋ด๊ฐ ์ํ๋ ๊ฐ์ด ๋์ค๊ฒ ๋๋ค.
Axios๋ Promise ๊ธฐ๋ฐ์ผ๋ก XHRHttpRequests ์์ฒญ์ ์ฝ๊ฒ ํ ์ ์์ต๋๋ค.
์์
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
์ฌ๊ธฐ์ {}
์์ ์๋ ๊ฒ์ด params
์ด๋ค.
import axios from 'axios';
import { METHOD } from './type';
const apis = axios.create({
baseURL: `${process.env.REACT_APP_CMS_URL}`, // ๊ธฐ๋ณธ ์๋ฒ ์ฃผ์ ์
๋ ฅ
});
const fetcher = async (method: METHOD, url: string, params?: any) => {
try {
// ๐ method = get, post, put, delete ์ฌ๋ถ & url = baseURL ๋ค์ ์ฌ api ์ฃผ์ & params ๋ config
const res = await apis[method](url, {params});
return res.data;
} catch (error: any) {
console.log('error-->', error);
return error;
}
};
export default fetcher;
fetcher ๋ผ๋ ๋ชจ๋์ ๋ง๋ค์ด์ ๋ฐ์ดํฐ ๋ถ๋ฌ์ฌ ๋ ๋งค๊ฐ๋ณ์ ๊ฐ์ ๋ฃ์ด ๋ฐ์์ค๋๋ฐ, ๋งค๊ฐ๋ณ์ ๊ฐ์
params
๋ผ๋ ์ด๋ฆ์ผ๋ก config ์ ๊ฐ์ ๋ฃ๋๋ค.
const res = await fetcher(METHOD.GET, `/api/v1/cms/notices`, {
pageNo: boardInfo.pageNumber,
pageSize: boardInfo.size,
categoryId: boardInfo.categoryId
});
fetcher
๋ผ๋ ๋ชจ๋์ ์ฌ์ฉํ ์์ ์ด๋ค. ์ธ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๊ฐ ๋ฐ๋ก config ์ญํ ์ ํ๋๋ฐ, ์ด config๋ api ์ฃผ์์ธ/api/v1/cms/notices
์ ํ๋ผ๋ฏธํฐ ์ญํ ์ ํด์ค๋ค./api/v1/cms/notices?pageNo=${boardInfo.pageNumber}?pageSize=${boardInfo.size}?categoryId=${boardInfo.categoryId}
๋ผ๊ณ ๋ณด๋ฉด๋๋ค.
AxiosRequestConfig
axios.get(url: string, config?: AxiosRequestConfig<any> | undefined)
์ด๋ฐ์์ผ๋ฃจ ์ง์ ํ์ฌ
const res = await axios.get('https://fake-api.kindacode.com/tutorials', {
params: {
paramOne: 'one',
paramTwo: 'two',
paramThree: 'three',
foo: 1,
bar: 2,
},
});
์ด๋ ๊ฒ config ๊ฐ์ ๋๊ฒจ ์ค ์๋์๋ค. ๋๊ฒจ์ค ๋๋ params
๋ผ๋ ๋ช
๋ช
์ผ๋ก ๋๊ฒจ์ค์ผํ๋ค.
์ ์์์๋ ๋ด์ฉ๊ณผ
https://fake-api.kindacode.com/tutorials?paramOne=one¶mTwo=two¶mThree=three&foo=1&bar=2
์ด url์ ๋์ผํ ๊ฒฐ๊ณผ๊ฐ์ ๋ํ๋ธ๋ค.
์ฐธ๊ณ : https://www.kindacode.com/snippet/axios-passing-query-parameters-in-get-post-requests/
์๋์ ๊ฐ์ด api ๋ณ์๋ฅผ ๋ง๋ค์ด์ setState์ ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ด์ค๋ค.
const domesticState = async (dayParams: {}) => {
const rankApi = await fetcher(METHOD.GET, `/domestic/rank?toDate=${dayParams}`);
const globalKrwApi = await fetcher(METHOD.GET, `/domestic/total?toDate=${dayParams}`);
const coinListApi = await fetcher(METHOD.GET, `/domestic/coinList?toDate=${dayParams}`);
setRankList(rankApi.data);
setGlobalKrw(globalKrwApi.data);
setCoinList(coinListApi.data);
};
useEffect(() => {
let polling = setInterval(() => {
domesticState(todayCall);
}, 60000);
if (clickDay.replaceAll('-', '') !== todayCall) {
clearInterval(polling);
domesticState(changeDay);
} else {
domesticState(changeDay);
}
// ํ์ด์ง์ ๋ฒ์ด๋ ๊ฒฝ์ฐ polling X
return () => {
clearInterval(polling);
};
}, [clickDay]);
๊ทธ๋ฆฌ๊ณ setInterval ๋ฅผ ์ฌ์ฉํ์ฌ ์ฃผ๊ธฐ ์๊ฐ์ ๋ฃ๊ณ (60000 = 1๋ถ)
1๋ถ์ ํ ๋ฒ์ฉ api๋ฅผ ์๋กญ๊ฒ call ์ํด์ผ๋ก์ ์ค์๊ฐ์ผ๋ก ๋ณ๋๋๋ api๋ฅผ ๋ณด์ฌ์ค ์๊ฐ ์๋ค.
๊ทธ๋ฆฌ๊ณ ๋ง์ผ์ ์กฐ๊ฑด์ ๋ฐ๋ผ polling์ ๋ฉ์ถ์ด์ผ ํ๋ค๋ฉด if๋ฌธ์ ์ฌ์ฉํด์ clearInterval
๋ฅผ ํด์ค๋ค.
clearInterval
๋ฅผ ํด์ค ๋๋ setInterval
๋ก id๊ฐ์ ๋ฃ์ด์ ์ค์ง์์ผ์ค๋ค !
๐๊ทธ๋ฆฌ๊ณ useEffect๋ฅผ ์ฌ์ฉํด์ ํ์ด์ง๊ฐ ๋ฒ์ด๋ ๋ willdidmount
๋์ ๋๋ฅผ ์๊ฐํด์๋ retrun๋ฌธ ์์๋ค๊ฐ clearInterval์ ํด์ค๋ค.
ํ์ผ์ ๋ณด์ด๋ ํด๋๊ฐ ๋ณด์ด์ง ์์ต๋๋ค.
- File -> Project Structure ํด๋ฆญ
- Modules ํด๋ฆญ
- +์ ๋๋ฌ Import Module ํด๋ฆญ ํฉ๋๋ค.
- ์์ ์ ํ๋ก์ ํธ Root ํด๋๋ฅผ ์ ํ -> Next ํด๋ฆญ
- OK ํด๋ฆญ
๋ ~~
์ด ๋ฐฉ๋ฒ์ด ์๋๋ค๋ฉด ๋ฃจํธ ๋๋ ํ ๋ฆฌ ์์ .idea ํด๋๋ฅผ ์ญ์ ํ๋ค๊ฐ ์ฌ์คํ ํ ๊ฒฝ์ฐ ์ค๋ฅ ํด๊ฒฐ๋๋ค๊ณ ํ๋ค.
์ซ์์์ BigNumber๋ฅผ ์์ฑํ ๋ BigNumber๋ toString()๊ธฐ๋ณธ ์ด์ง ๊ฐ์ด ์๋ ์ซ์์ 10์ง์ ๊ฐ์์ ์์ฑ๋ฉ๋๋ค. ํ์๊ฐ ํ์ํ ๊ฒฝ์ฐ ์ซ์ toString(2)๊ฐ์ ์ ๋ฌํ๊ณ ๊ธฐ์ 2๋ฅผ ์ง์ ํฉ๋๋ค.
BigNumber๋ฅผ ์ฐ๋ ์ด์ ๋ ํฐ ๋จ์์ ์๋ฅผ ์ฒ๋จ์(1,000)๋ก ํ๊ธฐํด์ฃผ๊ธฐ ์ํด์ ์ฌ์ฉํ๋ค.
new BigNumber(Number.MAX_VALUE.toString(2), 2)
npm install bignumber.js
์๋ฅผ๋ค์ด ํฐ ์๋ฅผ ๋ค๋ฃฐ ๋ ์ฐ๋๋ฐ ๋ณดํต ๊ธ์ก์ ์ธ ๊ฒ์ ๋ํด ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค.
๋ณ๋๋ฅ ๋ฑ๋ฝํ ๋ ๋น๊ต ๊ธฐ์ค์ ์ก๊ณ BigNumber ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฉ์๋์ค isGreaterThan์ 0๋ณด๋ค ๊ฐ์ด ํด ๊ฒฝ์ฐ ์ฌ์ฉ.
isLessThan์ 0๋ณด๋ค ๊ฐ์ด ์์ ๊ฒฝ์ฐ๋ฅผ ๋น๊ตํ์ฌ ์ด๋ค.
๊ทธ๋์ ์ฃผ์์ฐฝ ๊ฐ์๋ฐ๋ค ๋ฑ๋ฝํ์ํ ๋ up & dwon ์์
์ className์ ์ ์ฉํด์ ๋นจ๊ฐ์ ํ๋์์ ๋ํ๋ธ๋ค.
0์ผ ๋๋ ๊ฒ์ ์์ผ๋ก ์ ์ฉ์์ผ์ผ ๋จ.
{new BigNumber(Math.abs(oRowData.chgRate)).toFormat()}%
์ค์ view ๋จ์์ ํ๊ธฐ๋ ๊ฐ์ ์ค์ ๋ณ๋๋ฅ ๋ก ๋ณด์ฌ์ค๋ค.
์ด๊ฒ์ ์ฌ์ฉ ๋ฐฉ๋ฒ์ isEqual(๋งค๊ฐ๋ณ์1, ๋งค๊ฐ๋ณ์2)
๋ก ์ฐ์ด๋๋ฐ,
๋งค๊ฐ๋ณ์ 1๊ณผ ๋งค๊ฐ๋ณ์ 2๊ฐ ์๋ก ๊ฐ๋? ๋ผ๋ ๋ป์ผ๋ก ์ฐ๋ ๋ฉ์๋๋ค.
if (_.isEqual(oCoinData, oldRowData)) {
oldRowData.current = oCoinData;
setRowData(oCoinData);
}
โญ๏ธ props๋ก ํจ์ ๋ฐ์ดํฐ๋ ๋ด๋ ค๋ฐ์ ์ ์์
์ฐธ๊ณ ์๋ฃ
https://github.com/MikeMcl/bignumber.js
export const clip = (): void => {
let url = '';
const textarea = document.createElement("textarea");
document.body.appendChild(textarea);
url = window.document.location.href;
textarea.value = url;
textarea.select();
document.execCommand("copy");
document.body.removeChild(textarea);
}
const url = document.URL;
์ ์ญ ์ค์ ๊ณผ ๊ฐ์ ํ๊ฒฝ๋ณ์๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด env ํ์ผ์ ํ์ฉํ ์ ์๋ค.
์ฑ์ ๋ฒ์ ์ ๋ณด ๋๋ api ์ฃผ์์ ๊ฐ์ ์ ๋ณด๋ฅผ ์ ์ญ๋ณ์์ฒ๋ผ ์ฌ์ฉํ ์ ์๋ค.
$npm i env-cmd
์ค์น!
REACT_APP_
๋ก ์์ํด์ผ ํ๋ค.env ํ์ผ
REACT_APP_SERVER_API=http://localhost:8080
์ด๋ฐ์์ผ๋ก ์์ฉํ๋๋ฐ ์ฑ๊ธ ์ฟผํฐ๋ ํ์์๋ค.
๋ถ๋ฌ์ ์ฌ์ฉํ ๋๋ ์ด์ฒ๋ผ ์ฌ์ฉํ ์ ์๋ค.
const serverAPI = process.env.REACT_APP_SERVER_API
.env ํ์ผ์ ๊ฐ๋ฐํ๊ฒฝ๊ณผ ๋ฐฐํฌ์ ๋ฐ๋ผ ๋ค์์ ํ์ผ์ ์์ฑํ์ฌ ํ์ฉํ ์ ์๋ค.
์๋ฅผ ๋ค์๋ฉด ์ด๋ ๊ฒ.
.env-dev
.env-production
.env-local
.env-test
.env
์ฑ ๋น๋์ ๋ฐ๋ผ์ ์ ์ฉ๋๋ ํ์ผ ์ฐ์ ์์๋ ์ด์ ๊ฐ๋ค.
pagakage.json ํ์ผ์ script ๋ถ๋ถ
npm start: .env-dev, .env
npm run build: .env-production, .env
npm test: .env-test, .env
๋ชจ๋ env ํ์ผ์ ์ค์ฒฉ์ด ๋๊ณ ์ผ์ชฝ ํ์ผ์ด ์ฐ์ ์์๊ฐ ๊ฐ์ฅ ๋๋ค.
์ด ๋ง์ ์ฆ์จ ๋๊ฐ์ ํ๊ฒฝ๋ณ์๊ฐ ์ ์ธ๋ ๊ฒฝ์ฐ ์ฐ์ธก์ .envํ์ผ์ ๊ท์น์ด ๊ฐ์ฅ ์ฐ์ ์์๊ฐ ๋ฎ์.
๋ค๋ฆ๊ฒ ์ ์ธํ ์๋ก ์ฐ์ ์์ ๋ฎ์
"scripts": {
"start": "react-scripts start",
"build": "env-cmd -f .env react-scripts build",
"build:prod": "env-cmd -f .env.production react-scripts build && move build ./build_prod",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
.env.local ํ์ผ์ .env๋ฅผ ๋ฎ์ด ์ฐ๋ ํ์ผ๋ก test ํ๊ฒฝ ์ธ์ ๋ชจ๋ ํ๊ฒฝ์์ ๋ก๋ฉ๋๋ค.
$ npm run start
$ yarn start
.env.production ํ์ผ์ ๋ฐฐํฌ ํ๊ฒฝ ์ ์ฌ์ฉ๋๋ฉฐ, ์๋์ ๋ช ๋ น์ด๋ฅผ ์น๋ฉด ์๋์ผ๋ก ์ฌ์ฉ๋๋ค. ๋ง์ฝ, .env.production.local์ด ์๋ค๋ฉด, .env.production์ ๋ฎ์ด์ด๋ค.
$ npm run build
$ yarn build
$ npm run test
$ yarn test
npm install --save-dev --save-exact prettier
๋๋
yarn add --dev --exact prettier
JavaScript ๊ธฐ์ค์ผ๋ก,
Preferences > Languages & Frameworks > JavaScript > Prettier > Prettier package์์ prettier
๊ด๋ จ๋ ๊ฒฝ๋ก๋ฅผ ์ ํ
module.exports = {
bracketSpacing: false, // ๊ฐ์ฒด ๋ฆฌํฐ๋ด์ ๊ดํธ ์ฌ์ด์ ๊ณต๊ฐ
jsxBracketSameLine: true, // JSX ์์์ ๋ง์ง๋ง ๋ผ์ธ์ '>' ํน์๊ธฐํธ๋ฅผ ๊ฐ์ ๋ผ์ธ|๋ค์ ๋ผ์ธ
singleQuote: true, // ์ฟผํ
์ด์
๋งํฌ๋ฅผ 1๊ฐ|2๊ฐ
trailingComma: 'all', // ๋์ ','๋ฅผ ๋ถ์('es5'(๊ธฐ๋ณธ), 'none', 'all' 3๊ฐ์ ์ต์
)
tabWidth: 2, // ํญ์ ๋์ด
};
์ด์ ์ ์ปค๋ฐ ๋ด์ญ์ผ๋ก ๋๋๋ฆฌ๊ธฐ
ํฐ๋ฏธ๋ ์ฐฝ ์ฌ๋ ๊ณณ์์ git ํด๋ฆญ โ ์์
ํ ๋ธ๋ฐ์น์ ์์
๋ด์ญ (ํธ๋ฆฌ) ๋ณด๋ฉด ๋๋๋ฆฌ๊ณ ์ ํ๋ ์ปค๋ฐ๋ด์ญ์ ์ฐํด๋ฆญ โ Reset Current Branch to here ํด๋ฆญ โ Hard ์ ํํ๊ณ Reset ํด๋ฆญ ํ๋ฉด ๋๋ค.
์๋จ nav๋ฐ์์ git ํด๋ฆญ โ Fetch ํด๋ฆญ โ Fetch ์ฑ๊ณต์ ์ผ๋ก ๋จ๋ฉด ํ๋จ ์ค๋ฅธ์ชฝ์ ๋ธ๋ฐ์น๋ช ํด๋ฆญ โ ๊ทธ๋ผ ๋๋กญ๋ฆฌ์คํธ์ ๋ก์ปฌ ๋ธ๋ฐ์น๋ remote ๋ธ๋ฐ์น๊ฐ ์์ โ remote ๋ธ๋ฐ์น์ ์๋ ๋ธ๋ฐ์น ์ฒดํฌ์์ ํด์์ผํ๋ค.
ํ์ผ import ํด์ฌ ๋ ํ์ผ ๊ฒฝ๋ก ๊น๋ํ๊ฒ ๋จ์ด์ง๋๋ก ํ๋ ๋ฐฉ๋ฒ.
import fetcher from 'lib/api';
import { METHOD } from 'lib/type';
// jsconfig.json ๋๋ tsconfig.json
{
"compilerOptions": {
"baseUrl": "src"
}
}
ํ์ฌ ์ ๋ฌด ์์ ํ๋ฉด์ ๊ฐ์์์ฐ ์ฝ์ธ ์ธ๊ธฐ TOP 10 ์ ๋ฆฌ์คํธ ์์ดํ ๋ค์ด ์๋ ์ฌ๋ผ์ด๋๋๋ ์์ ์ ํ๋ค.
์๋ ์ฌ๋ผ์ด๋ ๊ตฌํ์ ๋ํ ๊ตฌ๊ธ๋ง ์์ ๋ค์ ์ฐพ์๋ณด๋ค๊ฐ CSS์ translateX ์ขํ๋ฅผ ์ด์ฉํ์ฌ ์ฌ๋ผ์ด๋ ๋์๋๋๋ก ์์
ํด๋ดค๋ค.
๋จผ์ ์ฒซ ํ์ด์ง ์ง์
ํ ๋๋ ์ฌ๋ผ์ด๋ ์์์ ์ธ 0๊ณผ ๊ฐ์์์ฐ์ li ๊ฐ ๋๋น๋งํผ ์์ง์ด๊ธฐ ์ํด useState๋ฅผ ์ฌ์ฉํ์ฌ ์ํ๊ด๋ฆฌ๋ฅผ ์ ์ธํ์
const [currentPos, setCurrentPos] = useState<number>(0); // ์์์ 0, ๋ณ๊ฒฝ๋ ์์น๊ฐ
์ฌ๋ผ์ด๋ ์คํฌ๋กค ํ์ ๊ฒฝ์ฐ ์ฌ๋ผ์ด๋ ์ ์งํ๊ธฐ ์ํด์ useEffect๋ก ์ ์ด
๊ทธ๋์ slideEvent์ด๋ผ๋ ์ฌ๋ผ์ด๋ ์ ์ง์์ผ์ฃผ๋ ์ด๋ฒคํธ ํจ์๋ฅผ ๋ฐ๋ก ์ ์ธํด๋๊ณ ,
์คํฌ๋กค์ ํ๊ฒ ๋ ๊ฒฝ์ฐ ์ฌ๋ผ์ด๋ ์ ์ง 1๋ฒ ์์
์ ํด์คฌ๋ค.
slideEvent ํจ์์๋ค setTimeout์ ์ฌ์ฉํด์ ์ผ์ ์๊ฐ์ ์ฃผ๊ณ ๋ฌดํ๋ฃจํ ๋๊ฒํด์ ์ฌ๋ผ์ด๋ ๋์๋๊ฒ ํ๋ค.
useEffect(() => {
$elSlide.current.addEventListener('scroll', slideEvent);
return () => {
if ($elSlide.current) {
$elSlide.current.removeEventListener('scroll', slideEvent);
}
};
}, []);
๊ทธ๋ฆฌ๊ณ ul ํ๊ทธ์ ์คํฌ๋กค ๋๋น๋ฅผ useRef๋ก ์ธก์ ํด์ ๋ณด๊ธฐ์ 2๋ฒ ์์
ํ๋ค.
x์ถ์ ์คํฌ๋กค ๋๋น ๋ฉ์๋ = element.current.scrollWidth
์ ์ ๋๋ฐ์ด์ค ๋๋น = element.current.clientWidth
<ul xss=removed>
<li></li>
<li></li>
<li></li>
(...)
</ul>
๊ทธ๋ฆฌ๊ณ ์์ฒ๋ผ useRef๋ก ์ก์ ul ํ๊ทธ์ ์ง์ ์ ์ผ๋ก ์คํ์ผ์ ์ค์ currentPos ์ํ๋ฅผ ์ ์ดํ๋ค.
๊ทธ๋์ ์ด ๋๋น ์ธก์ ์ ์ด์ฉํด์ ์คํฌ๋กค์ด ๋๋ฉด์ x์ถ์ ์คํฌ๋กค์ด ์ ์ฒด ๋๋น์ ๋์ ๋๋ฌํ์ ๊ฒฝ์ฐ
slideEvent
์ด ์ด๋ฒคํธ ํจ์์๋ค๊ฐ clearTimeout
๋ฉ์๋๋ก setTimeout
์ผ๋ก ๋์๋๋ ๊ฒ์ ์ฌ๋ผ์ด๋ ๋ฉ์ถ๊ฒ ํจ
๊ทธ๋ฆฌ๊ณ clearTimeout
ํ ๋๋ ์ด๊ฒ๋ useRef
๋ก ์ฝ๋ฐฑํจ์๋ฅผ ๋ฃ์ด์ค ๊ณ ์ ์์ด๋ ๊ฐ์ ์ ์ธํด์ผํ๋ค.
const slideId = useRef<{timeId: number}>({timeId: 0})
์ด๋ฐ์์ผ๋ก ์ฌ์ฉํ ์ ์์. ๊ทธ๋์ ์ด slideId๋ฅผ setTimeout
์ ๊ฑธ์ด์ฃผ๋ ๊ณณ์๋ค๊ฐ ๋์
ํ๊ณ , clearTimeout
ํ ๋๋
clearTimeout(slideId) ํด์ ํ๋ฉด setTimeout ๊ฑธ์ด์ค ๋์๋ค์ด ๋ฉ์ถ๋ค.
๊ทธ๋ฆฌ๊ณ ์๋๋ ๋ฑ๋ฑํ๊ฒ ์์ง์๋๋ฐ ์คํ์ผ ์ชฝ์๋ค๊ฐ
transition: 5s;
transition-timing-function: linear;
์์ ๊ฐ์ ์์ฑ์ ๋ฃ์ผ๋ ๋ถ๋๋ฝ๊ฒ ์์ง์๋ค.
๋ฉ์ธํ๋ฉด์๋ ์ฌ๋ผ์ด๋๊ฐ ๋ฏธ๋์ํ๊ณ , ์ถ์ฒ ํ๋ฉด์์๋ ์ฌ๋ผ์ด๋๊ฐ ๋์๋๊ฒ ํ๋ ค๋ฉด ์ด๊ฒ๋ useEffect
์๋ค๊ฐ ์กฐ๊ฑด๋ฌธ์ ๊ฑธ์ด์ main ํ์
์ด ์๋ ๊ฒฝ์ฐ (=์ถ์ฒ ํ์ด์งํ๋ฉด)์ ๋ง ์ฌ๋ผ์ด๋ ๋์๋๋ ์ด๋ฒคํธ๋ฅผ ํธ์ถํด์ค์ผ๋ก์ 3๋ฒ ์์
๋ ์๋ฃํ๋ค,
๐ ๊ทธ๋์ ๋ค ์์ ์๋ฃํ๊ณ ๋๋ ์ผ์ด๋ ์ด์
์ด๋ ๊ฒ translate
๋ฅผ ์ ์ดํ๋ฉด์ ์์
ํ๋ ์คํฌ๋กค์ด ์๋๋ ํ์์ด ์๊ฒผ๋ค.
์๋๋ฉด ์ด๋ฏธ translateX๊ฐ์ด ์ง๋๋ฒ๋ ธ๊ธฐ ๋๋ฌธ์ด๋ค ;;;
๐ ์๋ฌดํผ ์คํฌ๋กค์ ์ ์ฒด ๋๋น๊น์ง ๋๋ฌํ์ ๋ ๋ฉ์ถ๊ณ ์คํฌ๋กค์ด ๋๊ฒ ํ๊ธฐ ์ํ
ํด๊ฒฐ๋ฐฉ๋ฒ
requestAnimationFrame , cancelAnimationFrame, scrollTo (scrollLeft)
์์ ๊ฐ์ ๋ฉ์๋ ์ฌ์ฉํ๋ค.
setTimeout
์ฌ์ฉํ ๋๋ ๋ถ๋๋ฝ๊ฒ ์ ๋๋ฉ์ด์
์ ์ฃผ๋ ค๋ฉด ๋ณ๋๋ก ์คํ์ผ๋ ์ค์ผํ๋๋ฐ ์ด ๋ฉ์๋๋๐ ์ฌ์ฉ๋ฐฉ๋ฒ์ ์ด๋ ๋ค.
const fnSlideRender = () => {
if (!$elSlide.current) {
return;
}
// ์ฌ๋ผ์ด๋ X๊ฐ ์์น 0.3px์ฉ ์์ง์ด๊ธฐ
variable.current.slideCurrent += 0.3;
// ์คํฌ๋กค X์ถ ํ์ฌ ์์น (scrollLeft)
$elSlide.current.scrollLeft = variable.current.slideCurrent;
// ์ ๋๋ฉ์ด์
๋์ ์ํค๊ธฐ
variable.current.slideStop = requestAnimationFrame(fnSlideRender);
// X์ถ ๋๋น ๋๊น์ง ๋๋ฌ ์ ์ ๋๋ฉ์ด์
๋ฉ์ถ์ด
// ํ์ฌ ์ฌ๋ผ์ด๋ x๊ฐ์ด (์คํฌ๋กค ์ ์ฒด ๋๋น - ์ ์ ๋๋ฐ์ด์ค ๋๋น) ๋ณด๋ค ์๊ฑฐ๋ ํฌ๋ฉด
if (variable.current.slideCurrent >= variable.current.slideWidth) {
cancelAnimationFrame(variable.current.slideStop);
}
};
const variable = useRef<{
// ๋ฉ์ถ ์ฌ๋ผ์ด๋ 2์ด ๋ค ์ฌ์คํ
timeOutRePlay: NodeJS.Timeout | 0
}>({
timeOutRePlay: 0
});
(...)
const fnSameEvent = () => {
cancelAnimationFrame(variable.current.slideStop);
// setTimeout ์ด๋ฒคํธ๊ฐ 2๋ฒ ๊ฑธ๋ฆฌ์ง ์๋๋ก
variable.current.timeOutRePlay && clearTimeout(variable.current.timeOutRePlay);
// ๋ฉ์ถ ์ฌ๋ผ์ด๋ 2์ด ๋ค ์ฌ์คํ
variable.current.timeOutRePlay = setTimeout(() => {
// ๋ฉ์ถฐ์ง ๊ณณ left ์์น
variable.current.slideCurrent = $elSlide.current?.scrollLeft || 0;
// ์ฌ๋ผ์ด๋ ์คํ
variable.current.slideStop = requestAnimationFrame(fnSlideRender);
}, 2000);
}
setTimeout์ผ๋ก 2์ด ํ์ ์ฌ์คํ ๋๋๋ก ํ๋ค. ๊ทธ๋ฆฌ๊ณ clearTimeout์ ํด์ฃผ๊ธฐ ์ํด id๊ฐ์ ๋ฐ์์์ผ ํ๋๋ฐ useRef์๋ค๊ฐ timeOutRePlay ๋ผ๋ ๊ฐ์ ์ ์ฅํด์ clearTimeoutํ ๋ ์ด์๊ฐ์ ๊ฐ์ผ๋ก ์ด๋ฒคํธ๋ฅผ clear ์์ผฐ๋ค.
// addEventListener
const slideStopEvent = (eventName: string) => {
$elSlide.current && $elSlide.current.addEventListener(eventName, fnSameEvent, { passive: true });
};
// removeEventListener
const slideStopCleanUp = (eventName: string) => {
$elSlide.current && $elSlide.current.removeEventListener(eventName, fnSameEvent);
};
addEventListener๋ฅผ ํด์ค ๋ ์ฝ๋ ์์ passive: true๋ฅผ ์ ์ธํด์ค์ผ ํ๋ค.
๊ทธ ์ด์ ๋ passive ์ต์ ์ ๊ธฐ๋ณธ ๊ฐ์ ํญ์ FALSE๋ค. ๊ทธ๋ฌ๋ ์ด ๊ธฐ๋ณธ ๊ฐ์ผ๋ก ์ธํด ํฐ์น ์ด๋ฒคํธ ๋ฑ ์ผ๋ถ ์ด๋ฒคํธ์ ์์ ๊ธฐ๊ฐ ์คํฌ๋กค์ ์ฒ๋ฆฌ ์ค์ธ ๋ธ๋ผ์ฐ์ ๋ฉ์ธ ์ค๋ ๋๋ฅผ ๋ธ๋กํ ๊ฐ๋ฅ์ฑ์ด ์๊ธด๋ค. ๋ฐ๋ผ์ ์คํฌ๋กค ์ฑ๋ฅ์ด ํฌ๊ฒ ์ ํ๋ ์ ์๋ค.
๊ทธ๋์ ์ด ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ์ผ๋ถ ๋ธ๋ผ์ฐ์ ์์๋ ๋ฌธ์ ๋ ๋ฒจ ๋
ธ๋์ธ window
, document
, touchstart
, touchmove
์ด๋ฒคํธ์ ๋ํด์๋ passive์ ๊ธฐ๋ณธ ๊ฐ์ true
๋ก ๋ฐ๊ฟ์ ์ ์ฉํ๋ค.
์ด passive ์ด๋ฒคํธ ์์ ๊ธฐ๋ ์ด๋ฒคํธ๋ฅผ ์ทจ์ํ ์ ์์ผ๋ฏ๋ก ์ฌ์ฉ์๊ฐ ์คํฌ๋กคํ ๋ ๋ธ๋ผ์ฐ์ ์ ๋ ๋๋ง์ ๋ฐฉํดํ์ง ์๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋ ์คํ์ด๋ ๋ธ๋ผ์ฐ์ ๋ ๋๋ง์ ๋งก๋ ๋ฑ ๋ธ๋ผ์ฐ์ ์ ์ฃผ๋ ๋์์ด ์ํ๋๋ ๊ณณ์ด๋ค.
๋ค๋ฅธ ๋ชจ๋ฐ์ผ ๊ธฐ๊ธฐ์์๋ ์๋ฌด๋ฐ ํ์์ด ์์์ง๋ง ํน์ ํธ๋ํฐ์ธ <์์ดํฐ 10>์์ ๋ฐ์ํ๋ ์ด์์๋ค.
์ด๋ฌํ ํ์์ setInterval์ ์ฌ์ฉํ์ฌ ๊ฐ๋ฐํ์ฌ ๋ฐ์ํ ๊ฒ์. ์๋ฐ์คํฌ๋ฆฝํธ๋ก ์ ๋๋ฉ์ด์
์ ๊ตฌํํ ๊ฒฝ์ฐ 1์ด์ 60ํ๋ ์์ ์ฐ์ด๋ด๊ฒ ๋๋ค.
์ฆ 1ํ๋ ์์ ์ฐ์ด๋ด๋๋ฐ 16.6ms๋ฅผ ์ด๊ณผํ๊ฒ ๋ ๊ฒฝ์ฐ ๋ฆฌํ๋ก์ฐ ํ์์ด ์ผ์ด๋๋ค.
๋ฆฌํ๋ก์ฐ ํ์์ด๋ ๋ธ๋ผ์ฐ์ ๋ ๋๋งํ๋ ๊ณผ์ ์์ [๋ ์ด์์ - ํ์ธํธ - ํฉ์ฑ] ์ด๋ฐ ๊ณผ์ ์ด ๋ฐ์ํ๋ ๊ฒ์ธ๋ฐ, ์ด๊ฐ์ ํ์ ๋๋ฌธ์ ํ๋ฉด์ด ๋ฒ๋ฒ
๊ฑฐ๋ฆฌ๋ ์ด์๊ฐ ๋ํ๋๊ฒ ๋ ๊ฒ์ด๋ค. ๊ทธ๋์ ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ ์ ๋๋ฉ์ด์
์ ์ต์ ํ ํด์ฃผ๋ ๋ฉ์๋์ธ requestAnimationFrame
๋ฅผ ์ฌ์ฉํด์ ํด๋น ์ด์๋ฅผ ํด๊ฒฐํด ๋๊ฐ ์ ์์๋ค.
์ด ๋ฉ์๋๋ ๋ธ๋ผ์ฐ์ ๋ฆฌ์์ค์ ์ปดํจํฐ์ CPU ์ฑ๋ฅ์ ๊ณ ๋ คํ์ฌ 1์ด๋น ํ๋ ์ ์๋ฅผ ์กฐ์ ํด์ฃผ์ด ์ ๋๋ฉ์ด์
์ ์ต์ ํ ํด์ฃผ๋ ๊ธฐ๋ฅ์ด ์๋ค๊ณ ํ๋ค. ๊ทธ๋์ ์ด๋ฅผ ํตํด FPS (๋ชจ๋ํฐ ์ฃผ์ฌ์จ) ์ ์ดํจ์ผ๋ก์จ ์ต์ข
๊ฒฐ๊ณผ๋ฌผ์ ์ ๋๋ฉ์ด์
๋์ํ ๋ถ๋ค๊ฑฐ๋ฆผ ํ์์ด ์ฌ๋ผ์ก๋ค.
๊ทธ๋์ ์์ดํฐ10 ์์๋ ์ฝ์ธ๋ฆฌ์คํธ์ ์๋ ์ฌ๋ผ์ด๋๊ฐ ๋ถ๋๋ฝ๊ฒ ๋ ๋๋ง ๋๋๋ก ์ฑ๋ฅ ์ต์ ํ ๋จ
์ฐธ๊ณ ์๋ฃ : https://curryyou.tistory.com/520
$npm i moment
import moment from 'moment';
import 'moment/locale/ko';
const nowTime = moment().format('YYYY-MM-DD HH:mm:ss');
console.log('ํ์ฌ ์๊ฐ', nowTime);
์ด ์ํ๋ผ๋ฉด F5
ํค๋ฅผ ๋๋ ์ ๋๋ง ์๊ฐ์ด ๋ณ๊ฒฝ๋๋ค.
์ฐธ๊ณ https://overreacted.io/making-setinterval-declarative-with-react-hooks/
๊ฐ๋ต ์ค๋ช ํ๋ฉด, ๋ค์ ์ง๊ด์ ์ด์ง ์๋ค.
useInterval(() => {
// Your custom logic here
setCount(count + 1);
}, 1000);
์ด๊ฒ์ ์ฌ์ฉํ๋ ๊ฒ์ ๋ ์ถ์ฒํ๋ค. ์๋๋ฉด, ์ด๊ฒ๊ณผ setInterval์ ์ฐจ์ด์ ์ ์ธ์๊ฐ '๋์ '์ด๋ค.
// useInterval.js ์์ฑ
import { useRef, useEffect } from "react";
export default function useInterval(callback, delay) {
const savedCallback = useRef();
useEffect(() => {
// useEffect์ ๋งค๊ฐ๋ณ์๋ก ๋ฐ์ ์ฝ๋ฐฑ์ ํ์ฌ Ref๋ก ์ ์ธํด์ค๋ค.
savedCallback.current = callback;
});
useEffect(() => {
function tick() {
savedCallback.current();
}
// useEffect์ Ref์ current๋ฅผ setInterval๋ฅผ delay ์๊ฐ๋์ ํด์ค๋ค.
let id = setInterval(tick, delay);
// ์ธ๋ง์ดํธ๋๊ธฐ์ clearInterval์ ํด์ค๋ค.
return () => clearInterval(id);
}, [delay]);
}
useInterval
์ฌ์ฉํ๊ธฐ๐import { useInterval } from 'react-use';
const LiveTimeContainer = () => {
const [realTime, setRealTime] = useState(Date.now());
// useInterval
๐useInterval(() => {
setRealTime(Date.now());
}, 1000);
return <div>{seconds}</div>
}
import { Outlet, useLocation } from 'react-router-dom';
๋ฆฌ์กํธ ๋ผ์ฐํธ ๋์์ ์ ๊ณตํด์ฃผ๋ useLocation์ window.location
์ ์๋ฏธํ๋ค.
์ด๊ฐ ์ ๊ณตํ๋ ๋ฉ์๋๋ ์ด๋ฌํ๋ค.
const useLink = currentLocation.pathname.split('/')[1];
pathname์ /project/ํ๋ผ๋ฏธํฐ๊ฐ
์ด๋ ๊ฒ ์ถ๋ ฅ ๋๋๋ฐ, / ์ด ์ง๋๊ธฐ ๊ธฐ์ค์ผ๋ก ๋จ์ด๋ค์ ์ชผ๊ฐ ํ ๋ฐฐ์ดํ์์ผ์ ๊ฑฐ๊ธฐ์ project๊ฐ ์๋ ๊ฐ์ ๋ฝ์๋ด๋ฉด ๋๋ค.
์ค์ ๊ฐ -> ["", "project", "ํ๋ผ๋ฏธํฐ๊ฐ"] ์ด๋ ๊ฒ ์ถ๋ ฅ๋ผ ๋์จ๋ค.
๊ทธ๋ฌ๋ฉด ์ด์ , ๋ด๊ฐ ์ํ๋ ๊ฐ์ project์ด๊ธฐ ๋๋ฌธ์ const useLink = currentLocation.pathname.split('/')[1];
์ด๋ ๊ฒ ํํํ ๊ฒ์ด๋ค. [1]
const sameLink = (bgImgLink: string) => {
switch (bgImgLink) {
case 'project':
case 'document':
case 'member':
case 'faq':
return false;
default:
return true;
}
};
project, document, member, faq ๋จ์ด๊ฐ ๋ค์ด๊ฐ ๋งํฌ์๋ wrap์ด๋ผ๋ ํด๋์ค๋ฅผ ์ ์ฉํ๊ณ ์ถ์ง ์์์, switch ๋ฌธ์ผ๋ก ํด๋น ๋งํฌ์ผ ๋๋ split์ผ๋ก ์ชผ๊ฐ ํ์ฌ ์์น๋ฅผ ๋ฃ์ด์ return ์ false์ผ๋ก ์ถ๋ ฅ๋์ง ์๋๋ก ํ๋ค. ๊ทธ๋ฆฌ๊ณ ๊ธฐ๋ณธ์ ์ผ๋ก๋ wrap์ด๋ผ๋ ํด๋์ค๊ฐ ์ ์ฉ๋๋๋ก default ๊ฐ์ ture๋ก ํด์ฃผ์๋ค.
<div className={cx('ctnbody', sameLink(useLink) && 'wrap')}>
<Outlet />
</div>
์ด์ฒ๋ผ sameLink ๋ผ๋ ํจ์์ useLink ๋ผ๋ ์ชผ๊ฐ ํค์๋๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋๊ฒจ์ฃผ์ด์ ๊ทธ๊ฒ ํฉ๋นํ๋ค๋ฉด wrap์ด๋ผ๋ ํด๋์ค๋ฅผ ์ ์ฉ ํ๊ฑด ๋ง๊ฑด ํ๋ ์ฝ๋๋ฅผ ๊ตฌํํ๋ค.
project, document ... ๋ฑ๋ฑ์ ์ ์ธํ ๋๋จธ์ง ํ์ด์ง๋ค์ wrap์ด๋ผ๋ ํด๋์ค๊ฐ ์ ์ฉ๋๋ค.
OR ์ฐ์ฐ์์ธ || ๋ฅผ ์ฌ์ฉํด์
<div className={cx('ctnbody', sameLink('project' || 'member' || 'faq') && 'wrap')}>
<Outlet />
</div>
์ด๋ ๊ฒ ํ์๋๋ฐ ๊ทธ๋ ๊ฒ ํ๋ฉด ์ฒซ ๋ฒ์งธ ๊ฐ๋ง ์ธ์ ๋๋ค. ๊ทธ๋์ ๋ด๊ฐ ์ํ๋ ๊ฒฐ๊ณผ๊ฐ ์๋์์. ๋ด๊ฐ ์ํ๋ ๊ฒฐ๊ณผ๊ฐ ๋์ค๊ฒ ํ๋ ค๋ฉด switch ๋ฌธ์ผ๋ก ์กฐ๊ฑด์์ ์ ๋๋ก ๊ฑธ์ด์ ์์ ํด์ผ ๊ฒฐ๊ณผ๊ฐ ๋์๋ค.
์ฐธ๊ณ ํ๊ธฐ : https://ko.javascript.info/nullish-coalescing-operator
// ๋์ ์
let number = 20;
// ์ข์ ์
let myAge = 20;
์ด๋ฐ์์ผ๋ก ๊ตฌ์ฒด์ ์ผ๋ก ์ด๋ฆ์ ์ง๋ ๊ฒ์ ์ ํธํ๋ค.
์์ํ(๋จ์ผ ๋ฐ์ดํฐ)๊ณผ ๊ฐ์ฒดํ(๋ณตํฉ ๋ฐ์ดํฐ)์ผ๋ก ๋๋ ์๊ฐ ์๋ค. ๋จ์ผ ๋ฐ์ดํฐ (number, string, boolean, null, undefined, symbol) ๋ณตํฉ ๋ฐ์ดํฐ (object, array, function)
let integer = 123; // ์ ์
let negative = -123; // ์์
let double = 1.23; // ์ค์
let binary = 0b1111011; // 2์ง์
let octal = 0o173; // 8์ง์
let hex = 0x7b; // 16์ง์
๋ง์ผ ์ซ์๋ฅผ ์ถ๋ ฅํ ๋ ์ถ๋ ฅ๊ฐ์ด infinity๋ -infinity ๊ฐ์ด ๋์ค๋ฉด ์๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ซ์์ ํ
์คํธ๋ฅผ ์กฐํฉํ์ฌ ๊ณ์ฐ์์ ๋ธ๋ค๋ฉด NaN์ด๋ผ๋ ๊ฐ์ด ์ถ๋ ฅ๋๋ค.
'์๋
!', ${title}
์ด๋ฐ์์ผ๋ก ์ฌ์ฉํ ์ ์๋ค.let isFree = ture; // ์ฐธ์ธ ๊ฐ
let isActivated = false; // ๊ฑฐ์ง์ธ ๊ฐ
console.log(!!0); // flase ๊ฐ์ด ๋์จ๋ค.
console.log(!!-0); // flase ๊ฐ์ด ๋์จ๋ค.
console.log(!!''); // flase ๊ฐ์ด ๋์จ๋ค.
console.log(!!null); // flase ๊ฐ์ด ๋์จ๋ค.
console.log(!!undefined); // flase ๊ฐ์ด ๋์จ๋ค.
console.log(!!Nan); // flase ๊ฐ์ด ๋์จ๋ค.
console.log(!!1); // true ๊ฐ์ด ๋์จ๋ค.
console.log(!!-1); // true ๊ฐ์ด ๋์จ๋ค.
console.log(!!'text'); // true ๊ฐ์ด ๋์จ๋ค.
console.log(!!{}); // true ๊ฐ์ด ๋์จ๋ค.
console.log(!!Infinity); // true ๊ฐ์ด ๋์จ๋ค.
๋๋ํ 2๊ฐ๋ฅผ ๋ถํ๋ฉด ๊ฐ์ true๋ flase๋ก ๋ณํํ ์ ์๋ค.
๋๋ํ 2๊ฐ + ํ
ํ
๋น ์ ๋ค์ false ๊ฐ์ด ๋์ค๊ณ ๋๋ํ 2๊ฐ + ๋ฌด์ธ๊ฐ๊ฐ ์๋ ์ ๋ค์ true ๊ฐ์ด ๋์จ๋ค๊ณ ๋ณด๋ฉด ๋๋ค.
let title; // ์์ง ํ์ฑํ ๋ ๋ฌด์ธ๊ฐ๊ฐ ์๋์ง ์๋์ง ๋ชจ๋ฅด๋ ์ํ
title = null; // ํ์ฑํ๋ ๋ฌด์ธ๊ฐ๊ฐ ์๋ ์ํ
๊ทธ๋์ null์ ํ ๋นํ๋ฉด object๋ก ์ทจ๊ธํ๋ค.
ํ์ง๋ง undefined๋ ์๋ฌด๊ฒ๋ ํ์ ๋์ง ์์ ์ํ์ด๊ธฐ ๋๋ฌธ์ ์ฝ์๋ก๊ทธ์ ์ถ๋ ฅํ๊ฒ ๋๋ค๋ฉด ๊ทธ๋๋ก undefined๊ฐ ์ถ๋ ฅ๋๋ค.
{ key : value }
์ด๋ ๊ฒ ๋ํ๋ผ ์ ์๋ค.
์ฑ์ ๋ฉ๋ชจ๋ฆฌ ์์ data์ stack์๋ ์์ํ ๋ฐ์ดํฐ๊ฐ ๋ค์ด๊ฐ๊ฒ ๋๋ค. ๊ทธ๋ฆฌ๊ณ heap์กด์๋ ๊ฐ์ฒด๊ฐ ๋ค์ด๊ฐ๊ฒ ๋๋ค.
let apple = {
name: 'apple',
color: 'red',
display: '๐'
}
์ด๋ ๊ฒ ์๊ธด ๊ฒ์ ๊ฐ์ฒด๋ก ๋ณผ ์ ์๋ค.
let a = 1;
let b = a; // 1
b=2; // ์ฌํ ๋น์ ? ์ด์ 2๊ฐ ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ด๋ฐ ๋์์ด ๊ฐ์ฒด๋ก ๊ฐ๋ฉด ๋ฌ๋ผ์ง๋ค
let apple = {
name : 'apple'
}
let orange = apple;
apple.name = 'orange'
๋ผ๊ณ ๋ฐ๊พธ๋ฉด name์ด ๋์ผํ๊ฒ orange๋ก ๋ณ๊ฒฝ๋๋ค.
let a = 1;
a = 2; // ---> ๊ฐ๋ฅ
const text = 'hello';
text='bye'; // ---> ๋ถ๊ฐ.
const MAX_FRUITS = 5;
const apple = {
name: 'apple',
color: 'red',
display: '๐'
}
ํ์ง๋ง ๊ฐ์ฒด์ ์๋ ๋ด์ฉ๋ฌผ๋ค์ ๋ณ๊ฒฝํ ์ ์๋ ๋ฐฉ๋ฒ์ด ์๋ค.
apple.name = 'orange'; // ์ด๋ ๊ฒ ํด์ฃผ๋ฉด
console.log(apple); // ๊ฒฐ๊ณผ๊ฐ์ด ๋ฐ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์๋ค ๋ค์ด ๊ฐ๋ฅดํค๊ณ ์๋ ํน์ ํ object ๋ด๋ถ๋ฅผ ์์ ํ๋ ๊ฒ์ด๋ฏ๋ก ๋ณ๊ฒฝ์ด ๊ฐ๋ฅํ๋ค.
let variable;
console.log(typeof variable); // undefined
variable = '';
console.log(typeof variable); // string
variable = 1;
console.log(typeof variable); // number
์๋ฐ์คํฌ๋ฆฝํธ๋ ๋์ ์ผ๋ก ์คํ๋ ๋ ์ด๋ค ๊ฐ์ด ํ ๋น ๋๋๋์ ๋ฐ๋ผ ํ์ ์ด ๊ฒฐ์ ๋๋ค.
๋ชจ๋ ํ์ผ๋ค ๋ค๋ฅธ ํด๋์ ์ฎ๊ธฐ๊ธฐ
mv * ../
ls
ls -al
ios์์๋ ์คํฌ๋กค์ด ๋ถ๋๋ฝ๊ฒ ์์ง์ด์ง ์๋ ํ์์ ๋ฐ๊ฒฌํ๋ค.
์ฐธ๊ณ : https://github.com/magic-akari/seamless-scroll-polyfill
https://joonfluence.tistory.com/entry/IOS-Chrome-Safari%EC%97%90%EC%84%9C-Smooth-Scroll%EC%9D%B4-%EC%95%88%EB%90%A0-%EB%95%8C-%ED%95%B4%EA%B2%B0%EB%B2%95
html {
scroll-behavior: smooth;
}
document.getElementById(์์ด๋).scrollIntoView({
behavior: 'smooth',
});
lodash๋ ์๋ฐ์คํฌ๋ฆฝํธ์ ์ธ๊ธฐ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค ํ๋ ์ ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ์์ ๋ฐฐ์ด ์์ ๊ฐ์ฒด๋ค์ ๊ฐ์ ํธ๋ค๋ง ํ ๋ ์ ์ฉํฉ๋๋ค.
์ด๋ฌํ ์ ์ผ๋ก ์ธํด JS ์ ๋ณต์กํ ์๊ณ ๋ฆฌ์ฆ ์ฝ๋๋ฅผ ๊ตฌํํ ํ์ ์์ด lodash
๋ก ํ์ฌ๊ธ ์์ฝ๊ฒ ๊ตฌํํ ์ ์์ด์ ์ฝ๋๋๋ ์ค์ฌ์ฃผ๊ณ ๋น ๋ฅธ ์์
์ ๋์์ด ๋ฉ๋๋ค !
โญ๏ธ ํนํ front-end ํ๊ฒฝ์์ ๋ง์ด ์ฌ์ฉ๋ฉ๋๋ค.
$ yarn i --save lodash
$ yarn i --save @types/lodash
import _ from 'lodash';
(...)
_.(๋ฐฐ์ด๋ณ์)
var myFriend = [
{name:'kys',job:'developer',age:27},
{name:'cys',job:'webtoons man',age:27},
{name:'yhs',job:'florist',age:26},
{name:'chj',job:'nonghyup man',age:27},
{name:'ghh',job:'coffee man',age:27},
{name:'ldh',job:'kangaroo father',age:27},
{name:'hsy',job:'monk',age:27},
];
// ์ฝ๋ฐฑํจ์๋ฅผ ํตํด ๋์ด๊ฐ 26์ธ ๊ฐ์ฒด๊ฐ ์ฒ์์ผ๋ก ๋์ค๋ index ๋ฐํ
_.findIndex(myFriend, (friend) => {
return friend.age === 26;
});
_.flatten(arraym[isDeep])
์ฌ์ฉ๋ฒ
_.flatten([1, [2, 3, [4]]], true);
// โ [1, 2, 3, 4]
const myFriend = [
{'name':'๋ผ์ง'},
{'name':'๋ง๋ผํ'},
{'name':'๊ณฑ์ฐฝ'},
{'name':'ํ ์ด์คํ ๋ฆฌ'}
]
myFriend.map((item) => {
return {
item.name
}
}
_.map(mayFriend, 'name')
โจย ๊น๋ ๊ทธ์์ฒด โจ
๋ฆฌ์กํธ์์ HTML ์ฝ๋๋ฅผ ๋์ ์ผ๋ก ์ถ๊ฐํ๊ธฐ ์ํด์๋ ๊ธฐ์กด์ JS์์ ์ฌ์ฉํ๋ ๋ฐฉ์๊ณผ ๋ค๋ฅด๋ค.
๊ธฐ์กด์ ์๋ฐ์คํฌ๋ฆฝํธ์์๋ innerHTML๋ฅผ ์ฌ์ฉํด์ ๋ฃ์ด์ค๋ค๋ฉด ์ ์์ ์ผ๋ก ๋์ํ์ง๋ง ๋ฆฌ์กํธ์์๋ ์๋์ ๊ฐ์ด ์์
์ ํด์ผ ์ํ๋ ๊ฒฐ๊ณผ๊ฐ ๋์จ๋ค.
import React from 'react';
export default () => {
const htmlCode = "<div>์๋
</div>";
return <div dangerouslySetInnerHTML={{ __html: htmlCode }}>{htmlCode}</div>;
}
๋ฆฌ์กํธ์์๋ dangerouslySetInnerHTML={{ __html: htmlCode }}
์ด์ ๊ฐ์ ํํ๋ก ์ถ๊ฐํด์ค์ผํ๋ค.
const [htmlCode, setHtmlCode] = useState<string>('');
useEffect(() => {
try {
const getNotice = async () => {
const data = await httpService.get('๋ฐ์ดํฐ ์ฃผ์');
// ๋ณ๊ฒฝ ๋ ์ํ๊ด๋ฆฌ์ data.content ๋ฃ๊ธฐ
setHtmlCode(data.data.content);
};
getNotice();
} catch (error) {
console.log('error-->', error);
}
},[])
๋ฐํ์์ผ๋ก ๋งํ๊ธฐ
import produce from "immer";
// ๐ ์ด๊ธฐ์ํ ์ ์
const initialState = {
movies: [],
loadMovieLoading: false,
loadMovieDone: false,
loadMovieError: null,
};
// ํ๋ฉด ๋ก๋ฉ ๐ ํ์
์ ์
export const LOAD_MOVIES_REQUEST = "LOAD_MOVIES_REQUEST";
export const LOAD_MOVIES_SUCCESS = "LOAD_MOVIES_SUCCESS";
export const LOAD_MOVIES_FAILURE = "LOAD_MOVIES_FAILURE";
// ์ฒซ ๋ฒ์งธ ์ธ์ ํ์ฌ ์ํ (์ฆ, ์ด๊ธฐ์ํ)
// ๋ ๋ฒ์งธ ์ธ์ ์ก์
์ด ์ผ์ด๋์ผ ๋ ์ํ (dispatch)
// ๐ ๋ฆฌ๋์
const movies = (state = initialState, action) =>
produce(state, (draft) => {
switch (action.type) {
case LOAD_MOVIES_REQUEST: {
draft.loadMovieLoading = true;
draft.loadMovieDone = false;
break;
}
case LOAD_MOVIES_SUCCESS: {
draft.movies = draft.movies.concat(action.data);
draft.loadMovieLoading = false;
draft.loadMovieDone = true;
break;
}
case LOAD_MOVIES_FAILURE: {
draft.loadMovieError = action.error;
break;
}
default:
return state;
}
});
export default movies;
import axios from "axios";
import { all, fork, call, put, takeLatest, delay } from "redux-saga/effects";
import {
LOAD_MOVIES_REQUEST,
LOAD_MOVIES_SUCCESS,
LOAD_MOVIES_FAILURE,
} from "../reducers/movies";
function loadMoviesAPI() {
return axios.get("https://yts-proxy.now.sh/list_movies.json?sort_by=rating");
}
function* loadMainPosts() {
try {
console.log("saga Movies");
const result = yield call(loadMoviesAPI);
yield delay(1000);
yield put({
type: LOAD_MOVIES_SUCCESS,
data: result.data,
});
} catch (err) {
console.error(err);
yield put({
type: LOAD_MOVIES_FAILURE,
error: err.response.data,
});
}
}
function* watchLoadMainPosts() {
yield takeLatest(LOAD_MOVIES_REQUEST, loadMainPosts);
}
export default function* postSaga() {
yield all([fork(watchLoadMainPosts)]);
}
/*
๐ fork : ํจ์ํธ์ถ(๋น๋๊ธฐ)
๐ call : ํจ์ํธ์ถ(๋๊ธฐ)
๐ put : ์ก์
dispatch
๐ takeLatest : ์ก์
์ด dispatch๋๋ ๊ฒ์ ๊ธฐ๋ค๋ ค์ dispatch๋ ๋ generator๋ฅผ ํธ์ถ (๋งจ ๋ค์๊บผ๋ง)
๐ takeEvery : ์ก์
์ด dispatch๋๋ ๊ฒ์ ๊ธฐ๋ค๋ ค์ dispatch๋ ๋ generator๋ฅผ ํธ์ถ (์ ๋ถ)
*/
๋ฆฌ๋์ค๋ ์ด๋ฌํ ํ๋ก์ฐ๋ฅผ ์ง๋๋ค.
https://kyounghwan01.github.io/blog/React/mobx/async/#async-await-runinaction
https://velog.io/@wiostz98kr/TIL51-l-React-Router-3%ED%83%84
https://2oneweek.dev/frontend/react/006.%20Hook%20-%20useEffect/
https://velog.io/@ryong9rrr/componentDidMount-%EC%99%80-useEffect
https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-windowopen-%EC%A0%95%EB%A6%AC
๊ณตํต : ํด๋ํฐ ์ผ์ด๋ธ์ ์ฐ๊ฒฐํ๋ค.
์๋๋ก์ด๋ ๊ธฐ์ค ์๋์ฐ์, ์์ดํฐ์ผ ๊ฒฝ์ฐ์๋ ๋งฅ์๋ค๊ฐ ์ฐ๊ฒฐํด์ผํ๋ค.
โญ์ด ์ฃผ์๋ก ์ ๊ทผํ๊ธฐ -> chrome://inspect/#devices
chrome inspect ํด๋ฆญํด์ ํ์ธํ๋ฉด ๋๋ค.
์ฌํ๋ฆฌ ๋ธ๋ผ์ฐ์ ์์ ํ์ธ ํ ์ ์๋ค.
โญSafari -> ์๋จํญ์์ Develope -> ์์ดํฐ ์ด์ฉ๊ณ ์ ์ฉ๊ณ -> ๋๋ฒ๊น
ํด๋ฆญ
์์ดํฐ ์ค์ -> ์ฌํ๋ฆฌ -> ๊ณ ๊ธ -> ์๋ฐ์คํฌ๋ฆฝํธ, ์น์์ฑ ํ์ฑํ
๋๋ฒ๊น
ํ๋ฉด์์ ํญ [Sources]์ ๋ค์ด๊ฐ์ [Search] ์ ์์๋งํ ๋ด์ฉ ๊ฒ์ํ๋ฉด ๋ ๋นจ๋ฆฌ ์ฝ๊ฒ ์ฐพ์ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ ๋๋ฒ๊น
๊ฑธ ์์ค ์ฝ๋์๋ค๊ฐ ๋ธ๋ ์ดํฌ ํฌ์ธํธ (๋ง์ปค) ์ก๊ณ ๋๋ฒ๊น
ํ๋ฉด ๋๋ค.
ctrl + enter
๋ค์ ํ๋ก์ฐ์ ๋๋ฒ๊น ํ๋์ง ํ์ธํ ๋ ค๋ฉด F10 ๋๋ฌ์ ํ์ค ํ์ค ๋ค์ ์ฝ๋ ์คํํ๋ฉด ๋๋ค.
200 | ์ฑ๊ณต |
---|---|
400 | Bad Request,์๋ชป๋ ์์ฒญ์ผ๋ก์จย ๋ฌธ๋ฒ์ ์ค๋ฅ๊ฐ ์์ด์ย ์๋ฒ๊ฐ ์์ฒญ์ฌํญ์ ์ดํดํ์ง ๋ชปํ๋ ๊ฒฝ์ฐ ex) ์๋ชป์ ๋ ฅํ url์ธ๊ฒฝ์ฐ๊ฐ ๋๋ถ๋ถ! |
404 | Not Found,ํด๋ผ์ด์ธํธ๊ฐย ์์ฒญํ ๋ฌธ์๋ฅผ ์ฐพ์ง๋ชปํ ๊ฒฝ์ฐ์ ๋ฐ์ํจ ex) urlํ์ธ์ด๋ ์บ์์ญ์ ํด๋ณผ๊ฒ! |
405 | Method not allowed,๋ฉ์๋ ํ์ฉ์๋จ, Request๋ผ์ธ์ ๋ช
์๋ย ๋ฉ์๋๋ฅผ ์ํํ๊ธฐ ์ํ ํด๋น ์์์ ์ด์ฉ์ด ํ์ฉ๋์ง ์์์ ๊ฒฝ์ฐ ๋ฐ์ํจ.ย (ํ์ด์ง๋ ์กด์ฌํ๋, ๊ทธ๊ฑธ ๋ชป๋ณด๊ฒ ๋ง๊ฑฐ๋ ๋ฆฌ์์ค๋ฅผ ํ์ฉ์ํจ) ex) ์ฃผ๋ก ๋ฉ์๋ ๋งค์นญ์ด ์๋ ๋ ์ผ์ด๋จ |
415 | ์ง์๋์ง ์๋ ํ์์ผ๋ก ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญ์ ํด์ย ์๋ฒ๊ฐ ์์ฒญ์ ๋ํ ์น์ธ์ ๊ฑฐ๋ถํ ์ค๋ฅ๋ฅผย ์๋ฏธํ๋ค. ex) ContentType, Content Encoding ๋ฐ์ดํฐ๋ฅผ ํ์ธํ ํ์๊ฐ ์๋ค |
500 | ์๋ฒ ๋ด๋ถ ์ค๋ฅ๋ย ์น ์๋ฒ๊ฐ ์์ฒญ์ฌํญ์ ์ํํ ์ ์์ ๊ฒฝ์ฐ์ ๋ฐ์ํจ |
505 | HTTP Version Not Supported |
๊ณต์ง์ฌํญ์ ๊ฒ์๋ฌผ์ด ๋กค๋ง๋๋ ์์ ์ ํ์๋ค.
const [idx, setIdx] = useState(0);
const idxRef = useRef(0);
const [pressRelease, setPressRelease] = useState<MainPost[]>([]);
(...)
const getMainPressRelease = async () => {
try {
const res = await axios.get("/api/v1/cpc/main/board/list?board_master_id=CPC_PRESS_RELEASE&size=6");
const resMobile = await axios.get("/api/v1/cpc/main/board/list?board_master_id=CPC_PRESS_RELEASE&size=1");
setPressRelease(res.data);
setPressReleaseMobile(resMobile.data);
console.log(res.data);
} catch (error) {
console.log(error);
}
};
// api ๋ฐ์ดํฐ ๊ฐ๋์ํค๊ธฐ
useEffect(() => {
getMainPressRelease();
}, []);
// ๐ ๊ฐ์ฅ ์ค์ํ ๋ถ๋ถ์ด๋ค.
useEffect(() => {
// ๋กค๋ง๋๋๋ก setInterval์ ์ ์ธ.
const timer = setInterval(() => {
const rolling = Number(idxRef.current) + 1;
idxRef.current = rolling % 5; // ๊ฒ์๋ฌผ ๊ฐฏ์
setIdx(idxRef.current);
console.log(idxRef.current);
}, 3000);
// ๋ฌผ๋ก clearInterver๋ ์ค์ ํด์ค์ผํ๋ค.
return () => {
console.log("clean interval");
clearInterval(timer);
};
}, [ pressRelease.length]);
return (
<ul className={styles.article_list}>
{contents.map((item: MainPost) => (
<div key={item.id} style={{ transform: `translateY(-${28.8 * idx}px)`, transition: idx === 0 ? "" : "1s all" }}>
<li>
<Link className={styles.a} to={`/boardView/CPC_NOTICE/${item.id}`}>
<span className={styles.title}>{item.title}</span>
<span className={styles.date}>{moment(item.create_date).format("YYYY-MM-DD")}</span>
</Link>
</li>
</div>
))}
</ul>
)
.article_list {
font-size: 18px);
line-height: 1.3;
height: 50px;
overflow: hidden;
}
์ด๋ ๊ฒ ํด์ฃผ๋ฉด ์์ฑ !
https://safe.bithumbsystems.com/ --> ํด๋น ์ฌ์ดํธ ๋ฉ์ธ ๋ถ๋ถ์ ๊ณต์ง์ฌํญ์ด๋ ๋ณด๋์๋ฃ ๋ถ๋ถ ๋กค๋ง๋๋ ๋ถ๋ถ ๊ตฌํ ๋ด์ฉ์ ๋๋ค.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.