iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 7
1
Modern Web

Next.js + 各種套件組合系列 第 7

Next.js & Styled-component

介紹
styled-component(以下稱SC) 是目前Css In Js 呼聲最高的一個套件。 透過 SC 可以快速產生一個具有可傳 Props 的物件同時又具有指定 html 類型的特性,除了在生成元件上速度非常快,也有一些擴充性可再利用的特性,非常的方便也支援 Reactnative ,原本寫 Sass Less Css 也不用太擔心,因為他有支援 ES6 Template Literals LITERALS 可以直接用原來的風格撰寫

開始使用

安裝SC npm install --save styled-components

馬上使用 在創建一個 SC 只需要 import styled from styled-components 之後就可以馬上使用,如下方 styled 後面加上 HTML 物件例如 h1,button,section,div..等等
這樣就會具有該 HTML 的特性又具有 SC 的一些 Props 功能 ,使用創建出來的Tag 還可以包其他TAG做出不同組合

const Title = styled.h1`
	font-size: 1.5em;
	text-align: center;
	color: palevioletred;
`;

const Wrapper = styled.section`
	padding: 4em;
	background: papayawhip;
`;
render(
	<Wrapper>
		<Title>
			Hello World, this is my first styled component!
		</Title>
	</Wrapper>
);

利用 SC 創建的物件可以直接指定參數 例如 下方的 Button的primary 傳入後可以在 Props 裡面使用 props.primary接收到



const Button = styled.button`
	background: ${props => props.primary ? 'palevioletred' : 'white'};
	color: ${props => props.primary ? 'white' : 'palevioletred'};
	font-size: 1em;
	margin: 1em;
	padding: 0.25em 1em;
	border: 2px solid palevioletred;
	border-radius: 3px;
`;

render(
	<div>
		<Button>Normal</Button>
		<Button primary>Primary</Button>
	</div>
);


SC 也可以在既有的元件上再掛上 Style ,以下範例有一個Link 用Styled使用HOC 包裝起來再使用ES6 Template Literals 語法包起來

const Link = ({ className, children }) => (
	<a className={className}>
		{children}
	</a>
)

const StyledLink = styled(Link)`
	color: palevioletred;
	font-weight: bold;
`;

render(
	<div>
		<Link>Unstyled, boring Link</Link>
		<br />
		<StyledLink>Styled, exciting Link</StyledLink>
	</div>
);

SC 也提供了動畫功能 import {keyframes} from 'styled-component'定一個 keyframes 的動畫在 SC 裡面給 animation 用 ES6 Template Literals 傳遞動畫的使用也非常方便


const rotate360 = keyframes`
	from {
		transform: rotate(0deg);
	}

	to {
		transform: rotate(360deg);
	}
`;

const Rotate = styled.div`
	display: inline-block;
	animation: ${rotate360} 2s linear infinite;
	padding: 2rem 1rem;
	font-size: 1.2rem;
`;

render(
	<Rotate>< ? ></Rotate>
);

在Next.js 設定 Theme 的部分也是在目錄 pages 底下創建一個 _document.js 檔案 因為 SSR 的部分有些程式碼是不能寫在 React dom 節點,這邊 getInitialProps SC 提供了一個 ServerStyleSheet

renderPage 就是在 APP 渲染之前加上一個 sheet.collectStyles 的 Wrap ,然後也在 Head 底下把 sheet.getStyleElement() 產出的 Style 打上去這樣就會有 SSR 的效果了

import Document, { Head, Main, NextScript } from 'next/document'
import { ServerStyleSheet } from 'styled-components'

export default class MyDocument extends Document {
  static getInitialProps ({ renderPage }) {
    const sheet = new ServerStyleSheet()
    const page = renderPage(App => props => sheet.collectStyles(<App {...props} />))
    const styleTags = sheet.getStyleElement()
    return { ...page, styleTags }
  }

  render () {
    return (
      <html>
        <Head>
          <title>My page</title>
          {this.props.styleTags}
        </Head>
        <body>
          <Main />
          <NextScript />
        </body>
      </html>
    )
  }
}


Theme 的部分 在 TopLevel 定義好 ThemeProvider 底下的 SC 都可以拿到 Theme 如下範例

const Button = styled.button`
	font-size: 1em;
	margin: 1em;
	padding: 0.25em 1em;
	border-radius: 3px;
	color: ${props => props.theme.main};
	border: 2px solid ${props => props.theme.main};
`;

Button.defaultProps = {
	theme: {
		main: 'palevioletred'
	}
}

const theme = {
	main: 'mediumseagreen'
};

render(
	<div>
		<Button>Normal</Button>

		<ThemeProvider theme={theme}>
			<Button>Themed</Button>
		</ThemeProvider>
	</div>
);

使用 SSR 時候記得加上 .babelrc 檔案並安裝 Styled-component 的Plugin , 如果想要除錯方便也可以把 displayName 設定為 true 這樣在 className 的時候會多一個 component 的名稱,至於 preprocess 可以想成 Minify 性質是類似的,要使用的話則不能與 Minify 共用要選其一


{
  "presets": [
    "next/babel"
  ],
  "plugins": [
    ["styled-components", { "ssr": true, "displayName": true, "preprocess": false } ]
  ]
}

總結
SC 在 React 的元件組裝上非常的容易上手,並且容易擴充,而在 Next.js 上使用要記得在 _document.js 補上 getInitialProps 產出 Tag 放在 Head 中, 並使用 SC 提供的 ServerStyleSheet 的工具,配合 Next.js 提供的 renderpage 重新 Wrap App dom

Next.js 範例 參考來源
https://github.com/zeit/next.js/tree/canary/examples/with-styled-components

以上範例都可以在官網查詢到
http://styled-components.com


上一篇
Next.js & Material-UI
下一篇
Next.js & Typescript
系列文
Next.js + 各種套件組合30

尚未有邦友留言

立即登入留言