[FE302] React 基礎 ( hooks 版 ):React 基礎


Posted by s103071049 on 2021-09-03

  1. 開源專案的第一件事就是看 ReadMe
  2. 看任何 js 專案都從這個檔案開始 package.json,可以知道他用了什麼樣的 dependencies、
  3. 看 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 套件

  1. npm install --save styled-components
  2. 不用擔心兼容性的問題,會幫你自動加上瀏覽器的一些 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 的方式

  1. 字串:<TodoContent size="XL">i am todo</TodoContent>
  2. 變數:<TodoContent size={}>i am todo</TodoContent>

接收 props 的方式 ${function}

  1. 三元運算子寫法:font-size: ${props => props.size === 'XL' ? '20px' : '14px'},font-size 依據 props 動態決定
  2. 短路寫法:
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。


#JSX #切版 #React #Component







Related Posts

程式導師實驗計畫 week 2 題目與解答

程式導師實驗計畫 week 2 題目與解答

【單元測試的藝術】Chap 3: 透過虛設常式解決依賴問題

【單元測試的藝術】Chap 3: 透過虛設常式解決依賴問題

MTR04_0707

MTR04_0707


Comments