NEXT.js> styled-components
목표
화면 그리기
styled-components
SSR으로 인한 문제 발생 해결 코드
React에 styled-CSS를 적용했는데 새로고침과 함께 풀릴때가 많다. 서버 사이드 렌더링으로 인해 스타일 컴포넌트가 적용되지 않는 경우이다. 그런 경우는 다음과 같은 코드를 작성해주면 된다.
pages>_document.jsx
[_document.jsx]
import Document from "next/document";
import { ServerStyleSheet } from "styled-components";
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
try {
// sheet을 사용해 정의된 모든 스타일을 수집
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
});
// Documents의 initial props
const initialProps = await Document.getInitialProps(ctx);
// props와 styles를 반환
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
};
} finally {
sheet.seal();
}
}
}
.babelrc
[.babelrc]
{
"presets":["next/babel"],
"plugins":[["styled-components",{"ssr":true}]]
}
그리고 다음과 같이 npm 패키지를 다운받는다.
$npm i -D babel-plugin-styled-components
그리고 실행시킨다면 잘 실행이 될 것이다.
Custom-Hook
로그인
로그인을 하기 위해서는 아이디와 비밀번호의 입력을 받아야 한다. 여러개의 인풋을 제어하기 위한 방법으로는 여러가지가 있다.
여러개의 인풋을 제어하기위해서 제일 쉬운 방법은
const[input,setInput1]=React.useState('')
const[input2,setInput2]=React.useState('')
다음과 같이 각 변수를 선언해서 할 수 있다. 두번째로는 커스텀훅을 이용하면 같은 것을 한 함수에서 처리할 수 있다.
[login.jsx]
import FormLayout from '../../components/FormLayout'
import {useState} from 'react'
//여러개의 인풋 처리하기 위해서 사용
const useInput=(defaultValue)=>{
const [value,setValue]=useState(defaultValue)
const onChange=e=>{
const {value}={...e.target}
setValue(value)
}
return{value,onChange}
}
const Login =()=>{
const userid = useInput('');
const userpw = useInput('');
const handleSubmit =e=>{
e.preventDefault();
console.log(userid,userpw)
}
return (
<FormLayout>
<h2>로그인</h2>
<form onSubmit={handleSubmit}>
<input type ="text" {...userid} placeholder = "아이디를 입력해주세요"/>
<input type ="password" {...userpw} placeholder = "패스워드를 입력해주세요"/>
<button type ="submit">로그인</button>
</form>
</FormLayout>
)
}
export default Login
여기서 첫번째의
const[input,setInput1]=React.useState('')
const[input2,setInput2]=React.useState('')
const ChangeId=(e)=>{
const {value}={...e.target}
setInput1(value)
}
const ChangePw =(e)=>{
const {value} = {...e.target}
setInput2(value)
}
이처럼 반복되는 코드를 커스텀 훅을 이용하여
const useInput=(defaultValue)=>{
const [value,setValue]=useState(defaultValue)
const onChange=e=>{
const {value}={...e.target}
setValue(value)
}
return{value,onChange}
}
이렇게 줄인 것을 알 수 있다.
이를 이해하려면 먼저 babel을 이해해야 한다.
우리가 React에서 return 안에 쓴 내용들은 html 내용이지만 실제로는 javascript이다. 바벨이 javascript내용을 html으로 변환해주는 것임. babel은 {}안에 쓰면 자바스크립트 영역으로 인정해준다. 그리고 babel은 우리가 return 영역에 쓴 html(?)들을 다음과 같이 객체로 해석을 한다.
type="text" ------> "type":"text"
<input type = "text" value="ok"/>
<input type = "text" {...{"value":"ok"}} />
{value:"asdfasdf", onChange:()=>{alert(1)}
value="adsfadsf" onChange={()=>alert(1)}
여기서
<input type ="text" {...userid} placeholder = "아이디를 입력해주세요"/>
를 babel은 다음과 같이 해석한다.
(userid는 value값과 onChange로 이루어져 있다. )
userid={value:'',onChange:f}이기에
{...userid}
가 value="" onChange=f
가 되는 것을 알 수 있다.
<input type = "text" value={value} onChange={onChange} placeholder = "아이디를 입력해주세요"/>
와 같이 해석함 것을 알 수 있다.
변수값에 따른 렌더링 가능(단일 컴포넌트)
styled-component의 가장 큰 장점은 굳이 값을 주고 받는 과정이 없이도 변수를 통제해서 css를 조건부 렌더링 할 수 있다는 점이다.
예를들어 메뉴부분을 석삼(三)자로 만드는 메뉴같은 경우 , 클릭함에 따라 컴포넌트의 상태값을 변경하면서 그에 따라 메뉴를 나타내고 나타내지 않을 수 있는 것이다.
const Accordion = Styled.div`
...
display:${props=>(props.flag ? 'block' : 'none')};
...
`
위와 같이 Accordion에 styled-component가 적용된 코드가 다음과 같은 코드에 쓰인다면
const NavToggle =()=>{
const [visible,setVisible]=useState(false)//디폴트가 거짓
const handleToggle = ()=>{
setVisible(!visible)
}
return(
<Toggle>
<input
type = "checkbox"
id ="nav-toggle"
className = "nav-toggle"
onClick={handleToggle}
/>
<label htmlFor ="nav-toggle">
<span></span>
<span></span>
<span></span>
</label>
{/* {메뉴생성} */}
<div>
<Accordion flag ={visible}>
<ul>
<li>대분류메뉴1</li>
<li>대분류메뉴2</li>
<li>대분류메뉴3</li>
<li>대분류메뉴4</li>
<li>대분류메뉴5</li>
</ul>
</Accordion>
</div>
</Toggle>
)
}
export default NavToggle
visible이라는 변수값에 따라 값을 올리고 내리고 하지 않아도 컴포넌트 내에서 충분히 css 변경이 가능하다.
styled-components에서는 ${}으로 Javascript 문법을 사용할 수 있다.
변수값에 따른 렌더링 가능(여러 컴포넌트)
로그인 로그아웃 기능
로그인과 로그아웃을 하려면 javascript에서는 session이나 쿠키값을 이용했었다. react에서는 context와 reducer, 이 둘을 이용해서 할 수 있다. context와 reducer가 선언되어야 하는 부분은 최상위 컴포넌트이다.
Next.js에서는 여러 상위 컴포넌트가 많지만 우리가 사용할 값을 넣어야 하는 곳은 App컴포넌트이다. 우리가 저번에 만든 _app.jsx파일의 부분에 우리가 만든 모든 컴포넌트가 담긴다.
pages>_app.jsx
[_app.jsx]
import'../index.css'
import Head from 'next/head'
import Store from './store/context'
import {useReducer,useContext} from 'react'
import reducer from '../pages/store/reducer'
const App=({Component})=>{
const globalContext=useContext(Store)
const [state,dispatch] = useReducer(reducer,globalContext)
return (
<>
<Head>
<link/>
<link rel="preconnect" href="https://fonts.googleapis.com"/>
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="true"/>
<link href="https://fonts.googleapis.com/css2?family=Do+Hyeon&display=swap" rel="stylesheet"/>
</Head>
<Store.Provider value ={state,dispatch}/>
<Component/>/{/*우리가 만든 모든 것이 components에 위치한다. */}
<Store.Provider/>
</>
)
}
export default App
_app.jsx파일의 부분에 우리가 만든 모든 컴포넌트가 담긴다.
<Store.Provider value ={state,dispatch}/>
와 같이 state와 dispatch를 모든 컴포넌트에 넘긴다. 그러면 각 컴포넌트의 dispatch를 통해 _app.jsx에 있는 reducer가 실행된다.
pages>store>context.jsx
[context.jsx]
import {createContext} from 'react'
export const initialState ={
IsLogin:false,
}
const Store = createContext(initialState)
export default Store
pages>store>reducer.jsx
export const reducer =(state,action)=>{
switch(action.type){
case "LoGIN":
return state;
case "LOGOUT":
return {
...state,
IsLogin:false
}
case "":
return state
default:
return state;
}
}
이렇게 설정하고 login화면에서 값을 넘겨준다.
userid.value==="nara7875" && userpw.value ==="1234"
? Router.push('/')
:alert('아이디와 패스워드가 다릅니다')
}
c.f
Router.push('/'): 내가 원하는 경로로 이동
Author And Source
이 문제에 관하여(NEXT.js> styled-components), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@nara7875/next.js저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)