- 開源專案的第一件事就是看 ReadMe
- 看任何 js 專案都從這個檔案開始 package.json,可以知道他用了什麼樣的 dependencies、
- 看 src 的 index.js,
<React.StrictMode> </React.StrictMode>
,採用嚴格模式會幫我們檢查一些不該使用的東西,為了偵測事情有些地方會重複呼叫,所以 console.log 有時會出現跟你想的不一樣的狀況。一般來說會建議將這個拿掉。
ReactDOM.render(
<App />,
document.getElementById('root')
);
component return 後面要跟東西,不然會自動幫你補成 undefined。
jsx 有用到 js 相關的都要用 { } 包住
function Description(props) {
return (
<p>
{props.children }
</p>
)
}
也可以用解構的語法將 props 的東西拿出來
function Description({children}) {
return (
<p>
{children}
</p>
)
}
根據不同參數回傳不同東西
function Title({size}) {
if (size === 'XL') {
return <h1>hello</h1>
}
return (
<h2>hello</h2>
)
}
一個 component 的 props,就是你在 render 傳進去的東西,property 的簡寫。我們用解構的寫法就不用再多寫一次。
react 要如何與 style 做掛勾 ?
style 裡面要傳物件 <h2 style = {titleStyle} >hello</h2>
import logo from './logo.svg';
import './App.css';
const titleStyle = {
color: 'red', // js 裡面寫所以命名規則是駝峰式
textAlign: 'center'
}
// component 是 function 記得大寫開頭
function Title({size}) {
if (size === 'XL') {
return <h1>hello</h1>
}
return (
<h2 style = {titleStyle} >hello</h2> // 右鍵檢查就會發現東西有了 inline style
)
}
function Description({children}) {
return (
<p>
{children}
</p>
)
}
// 沒有要傳東西,可以用自己閉合的標籤寫,例如:<Title/>
function App() {
return (
<div className="App">
<Title size="M"/>
<Description>
哈囉你好嗎
衷心感謝
</Description>
</div>
);
}
export default App;
初探 React 中的 style
(一)、傳物件搭配 style 屬性
const titleStyle = {
color: 'red',
textAlign: 'center'
}
function Title({size}) {
if (size === 'XL') {
return <h1>hello</h1>
}
return (
<h2 style = {titleStyle} >hello</h2>
}
更常見的寫法,寫出來會是兩個大括號,第一個大括號是我要放的參數(用到 js 的地方都要用 { })、第二個是我要傳的東西。
缺:不支援偽元素,僅支援這個 element 的 inline style
(二)、css + className
class 是 jsx 的保留字,要用 className。<div className="App">
,當我傳 className = App,他 render 到瀏覽器的畫面上就會出現 <div class="App">
。因為 webpack,所以可以直接 import css 的檔案進來 import './App.css';
當然只要調整 webpack 設定 css 檔案也可換成 scss 或 sass。
(三)、styled-component 套件
- npm install --save styled-components
- 不用擔心兼容性的問題,會幫你自動加上瀏覽器的一些 prefix
``
用途
1. template string `${}`
2. function call (tagged template) 可以參考 pj 大文章
Description 就是有了 style 這個 p 的 component。他會預設有個 className,這個 className 是 style component 幫我加的。
component 開頭都要大寫。
// 原理:動態產生 className,將 className 放在 component 上,產生 css
const Description = styled.p`
color: red;
padding: 20px;
border: 1px solid gray;
`
const TitleWrapper = styled.h2`
display: flex;
color: red;
&: hover {
color: black
}
span {
color: green
}
`
function Title({size}) {
return (
<TitleWrapper>hello <span>dear</span></TitleWrapper>
)}
練習:切 todo 的 item
用了 style component 基本上就不會再寫 css 了。
傳 props 的方式
- 字串:
<TodoContent size="XL">i am todo</TodoContent>
- 變數:
<TodoContent size={}>i am todo</TodoContent>
接收 props 的方式 ${function}
- 三元運算子寫法:
font-size: ${props => props.size === 'XL' ? '20px' : '14px'}
,font-size 依據 props 動態決定 - 短路寫法:
const TodoContent = styled.div`
color: blue;
font-size: 12px;
${props => props.size === 'XL' && `
font-size: 20px;
`}
`
基礎寫法
import logo from './logo.svg';
import './App.css';
import styled from 'styled-components'
const TodoItemWrapper = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 16px;
border: 1px solid gray;
`
const TodoContent = styled.div`
color: blue;
font-size: 12px;
${props => props.size === 'XL' && `
font-size: 20px;
`}
`
const TodoButtonWrapper = styled.div``
const Button = styled.button`
padding: 4px;
color: black;
& + & {
margin-left: 6px;
}
&:hover {
color: red;
}
`
function App() {
return (
<div className="App">
<TodoItemWrapper>
<TodoContent size="XL">i am todo</TodoContent>
<TodoButtonWrapper>
<Button>已完成</Button>
<Button>刪除</Button>
</TodoButtonWrapper>
</TodoItemWrapper>
</div>
);
}
export default App;
常見寫法
function TodoItem ({size, content}) {
return (
<div className="App">
<TodoItemWrapper>
<TodoContent size={size}>{content}</TodoContent>
<TodoButtonWrapper>
<Button>已完成</Button>
<Button>刪除</Button>
</TodoButtonWrapper>
</TodoItemWrapper>
</div>
)
}
function App() {
return (
<div className="App">
<TodoItem content={123} />
<TodoItem content={456} size="XL"></TodoItem>
</div>
);
}
尚未處理:rwd、sass 變數
styled component 實戰
推薦將官方文件 basic 的部份看過一遍,這樣就會知道這套工具有哪些用法。
一、re-styled
(1) 對 style component 做 re-styled
const Button = styled.button`
padding: 4px;
color: black;
& + & {
margin-left: 6px;
}
&:hover {
color: red;
}
`
const RedButton = styled(Button)`
color: red;
`
function TodoItem ({size, content}) {
return (
<div className="App">
<TodoItemWrapper>
<TodoContent size={size}>{content}</TodoContent>
<TodoButtonWrapper>
<Button>completed</Button>
<RedButton>deleted</RedButton>
</TodoButtonWrapper>
</TodoItemWrapper>
</div>
)
}
(2) 對一般的 component 做 re-styled,因為 style component 背後原理是透過傳 className,所以我需要對目標的 component 給他一個 className,並將他放到相對應的地方。
function TodoItem ({ className, size, content}) {
return (
<div className="App">
<TodoItemWrapper className = {className}>
<TodoContent size={size}>{content}</TodoContent>
<TodoButtonWrapper>
<Button>completed</Button>
<RedButton>deleted</RedButton>
</TodoButtonWrapper>
</TodoItemWrapper>
</div>
)
}
const BlackTodoItem = styled(TodoItem)`
background: black;
`
二、rwd
const Button = styled.button`
padding: 4px;
font-size: 20px;
color: black;
& + & {
margin-left: 6px;
}
&:hover {
color: red;
}
@media screen and (min-width: 768px) {
font-size: 16px;
}
`
優化方式:新增一個資料夾(mkdir constants),將 style component 進行相對應的切開。
constants 資料夾裡面的 style.js
export const MEDIA_QUERY_MD = '@media screen and (min-width: 768px)'
export const MEDIA_QUERY_LG = '@media screen and (min-width: 1200px)'
app.js
import {MEDIA_QUERY_MD, MEDIA_QUERY_LG} from './constants/style'
const Button = styled.button`
padding: 4px;
color: black;
& + & {
margin-left: 6px;
}
&:hover {
color: red;
}
${MEDIA_QUERY_MD} {
font-size: 30px;
color: blue;
}
${MEDIA_QUERY_LG} {
font-size: 20px;
color: green;
}
`
三、sass 之類的變數怎麼做 ?
建議將 advanced 裡面的 theming 也看個。
提供一個 global 的參數,在不同檔案就可以使用 color: ${props => props.theme.main};
首先要有個 theme provider。
// index.js
import { ThemeProvider } from 'styled-components'
const theme = {
colors: {
red_300: '#ff7979',
red_400: '#e33e3e',
red_500: '#af0505'
}
}
ReactDOM.render(
<ThemeProvider theme={theme}>
<App />
</ThemeProvider>
,
document.getElementById('root')
);
app.js 透過上述方式達成類似 sass 的變數功能
const TodoContent = styled.div`
color: ${props => props.theme.colors.red_500};
font-size: 12px;
${props => props.size === 'XL' && `
font-size: 20px;
`}
`
components 多了,可以獨立成一個檔案。通常 component 都用 export default
一探 JSX 背後的秘密
魔法:透過 babel 轉成 js code。
EX1 babel 轉換:<button size="XL">hello</button>
,轉換後
"use strict";
/*#__PURE__*/
React.createElement("button", {
size: "XL"
}, "hello");
EX2 等價:將 <Button>已完成</Button>
進行 babel 轉換。兩種寫法是等價 !
import React from 'react'
function TodoItem ({size, content}) {
return (
<div className="App">
<TodoItemWrapper>
<TodoContent size={size}>{content}</TodoContent>
<TodoButtonWrapper>
{React.createElement(Button, null, "\u5DF2\u5B8C\u6210")}
<Button>刪除</Button>
</TodoButtonWrapper>
</TodoItemWrapper>
</div>
)
}
EX3 event handler:<Button size = 'XL' onclick = {() => {alert(1)}}>已完成</Button>
,他也是當作一個 props 傳進去。
他只是一個 function ,幫你把 function object、children 傳進去,
"use strict";
/*#__PURE__*/
React.createElement(Button, {
size: "XL",
onclick: () => {
alert(1);
}
}, "\u5DF2\u5B8C\u6210");
EX4 children 是另一個 component:第三個參數再 create 一個 React 的 element <Button size = 'XL' onclick = {() => {alert(1)}}>
completed<div>unsure</div></Button>
"use strict";
/*#__PURE__*/
React.createElement(Button, {
size: "XL",
onclick: () => {
alert(1);
}
}, "completed", /*#__PURE__*/React.createElement("div", null, "unsure"));
歷史補充:js 17 前有用到 jsx 的檔案都要 import React from 'react'
,因為 babel 轉換完成會用到 React.createElement。