Try   HackMD

[第03堂] React基礎知識-教材篇

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
小複習:

  • Node.js:開源的 JavaScript 執行環境
  • NVM:Node 的版本管理器
  • NPM:Node 的套件管理器
  • NPX:一樣是Node 的套件管理器,不過用完就會刪掉。

ES5/ES6

ES的全名是ECMAScript,是一個由Ecma International訂定的腳本語言標準化規範,JavaScript就是根據這個規範去訂定的,傳送門

ES5

  • 嚴格模式
  • Array/Object操作的方法
    • Array.find
    • Array.filter
    • Array.map

ES6

  • let & const
    • let可變動
    • const不可變動,宣告時要給定initialize
//let let a; a=10; console.log(a); a=20; console.log(a); //const const b=100; console.log(b); //下面可以拿掉註解測試看看 //b=200; //console.log(b);
  • 箭頭函式 Arrow Functions
//不帶參數 //ES5 function func_name(){ console.log('Hello World!'); } //ES6 func_name = () =>{ console.log('Hello World!'); } //帶一個參數 //ES5 function func_name(e){ console.log(e); } //ES6 func_name = e =>{ console.log(e); } //帶兩個(含)以上參數 //ES5 function func_name(e,i){ console.log(e,i); } //ES6 func_name = (e,i) =>{ console.log(e,i); } //關於return func_name = () => something func_name = () =>{ return something; }
  • 參數預設 Default Parameters
    傳入function的參數沒有給定值時,會出現Exception,最快的解決方法就是給定預設值,在ES6中給定預設值的方式更為快速簡單
BMI=(height=1.75, weight=65) => { let BMI=weight/(height^2); console.log(BMI); }
  • 文字模板 Template Literals
// ES5 var name='Jack'; var start = 'Hello'+name+'!'; //ES6 const name='Jack' const start = `Hello ${name}!`
  • 多行字串輸入 Multi-line Strings
// ES5 var fruit = 'apple,' + 'banana' //ES6 const fruit = `apple, banana`
  • 解構賦值 Destructuring Assignment
    他是在ES6的新特性
const Jack={age:40,gender:'male'}; //一般 console.log(Jack.age,Jack.gender); //解構 const {age,gender}=Jack; console.log(age,gender); //賦值 const Jack {age:x} = {age:40}; //x=40
  • 物件實字 Enhanced Object Literals
    假如object內的元素其key與value名稱一樣,可以省略key直接寫 value 名稱即可。
// ES5 var name = 'Jack'; var obj = { name: name }; // ES6 const name = 'Jack'; const obj = { name };
  • Promises
    非同步專用

JSX

JavaScript XML,JavaScript 的語法擴充,屬性名稱以小駝峰方是撰寫,要比較留意的是最外層只能有一個根元素。

下面的標籤語法不是一個字串也不是HTML,而是把右邊的HTML當成一個物件存到變數中,這種把HTML寫在JavaScript的程式碼中的技術,我們稱之JSX。

const element = <h1> 你好,世界!</h1>;

可以在HTML標籤中利用「{}」寫JavaScript表示式。

const showOne=true; const element = <h1>{showOne?1:0}</h1>

或是將style變為一物件、屬性名稱規則改用駝峰法(用大寫區隔)、屬性的值變成字串。

const styleArgument={ fontSize: '100px', color: 'red' }; ReactDOM.render( <h1 style={ styleArgument }> Hello, world! </h1>, document.getElementById('root') );

在JSX中的HTML標籤屬性基本上都與原本的HTML標籤屬性相同,比較特別的是class和for是js的保留字,因此這兩個屬性在JSX需要寫成classNamehtmlFor

<div className="title">標題</div>

因為JSX 並不是單純的 JS ,所以是沒辦法直接被套用在網頁上的,這時候就必須要透過 babel 進行轉譯並搭配 Webpack 進行打包的動作。

而透過babel進行轉役會變成怎麼樣子呢?

<a href="https://facebook.github.io/react/">Hello!</a>

例如上面的Hello world! 透過 babel 編譯後會轉成下面 React library 的 React.createElement() function calls。

// React.createElement(元件/HTML標籤, 元件屬性,以物件表示, 子元件) React.createElement('a', {href: 'https://facebook.github.io/react/'}, 'Hello!')

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
不過 React 並不要求使用 JSX,只是與createElement相比,JSX可閱讀性比較高。

下面會簡單介紹一些JSX的寫法

  • 變數:用 {} 包起來
const name = 'Andy' const htmlA = <h1>Hello {name}<h1> const htmlB = <h1>`Hello ${name}`<h1>
  • 多行的 HTML:最外層多加一個 ()
const html = ( <div> <span>Hello Andy</span> </div> )
  • if:改寫成三元運算子
    { } 中只能放 JavaScript expression,而if 是一個 JavaScript statement,所以在 JSX 無法使用 if。
const showOne=true; const element = <h1>{showOne?1:0}</h1>
  • html標籤中的數字
    如果值是數字,JSX 會幫你加上 "px" 單位,若不想用 px 就得明確指定單位。
// 值同 10px <div style={{ height: 10 }}> Hello World! </div>

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
小練習

  • 寫一個有底色、寬100%、高50px的div (用inline style)
  • 宣告 a = Hello
  • 在div中顯示Hello world (Hello必須是變數a)

Scss

現今主流的CSS預處理器之一

  • 巢狀結構
#banner{ ... #logo{ // 等同於 #banner #logo ... img{ // 等同於 #banner #logo img ... } } nav{ //等同於 #banner nav ... } }
  • &連接
a{ color:red; &:hover{ //等同於 a:hover color:red; } &:active{ //等同於 a:active color:blue; } }

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
小練習

  • 將css改用引入css檔案的方式撰寫

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

Components

我們稱之元件,Component 的字首須為大寫字母

React 提供了兩種元件實做方式,分別為Class & Functional,

Class Component

使用 Class(類別) 建立的元件,具有生命週期,具有State,擁有this,需要引入React Component,一定要實作render。

import React, { Component } from "react"; export default class Button extends Component { //用extends去繼承Component constructor(props) { super(props), } const handleButtonClick =()=>{ console.log('click'); } render() { //用render()函式去收集要渲染到畫面上的東西(放在return值),再去改變DOM return <button onClick={this.handleButtonClick}>btn</button>; } }

Functional Component

使用 Function(函式) 建立的元件,沒有生命週期,沒有State,編譯更快(因為不用將class轉換成es5)

function Button(props) { const handleButtonClick =()=>{ console.log('click'); } return <button onClick={handleButtonClick}>btn</button>; }

不過在Hook出現後Functional Component 也具有生命週期以及State。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Hook
在 React 16.8 引入的一種特性,可以在函數式組件中使用 React 功能的 API。以前如果想在元件中使用生命週期、State 等,一定要使用 Class 元件,直到 Hook 出現後,不使用 Class 的情況下也能具有生命週期以及State。

Props & State

React 中 Component 只能透過資料狀態的改變來更新 UI,而 React 元件有兩種資料來源:

  • 透過外部傳進來元件的 Props
  • 元件內部自己維護的 State

props

properties的縮寫,屬性。
用於元件與元件間傳遞資料,是靜態(唯讀)的。

state

內部狀態
元件存放資料的地方,以物件的方式存放(key:value),需要在constructor建立自身state,並且利用setState去改變state的值。

// Class寫法 constructor(props) { super(props); // 建立state並給予初始值 this.state = { currentPage: 'one', } } // 利用this.setState 改變state的值 this.setState({ currentPage:'two', }) // Hook寫法 const [page,usePage] = useState("one"); usePage("two");

constructor 是在 Component 建立的時候自動執行的 function,所以如果沒有要做任何事情的時候,可以不用寫 constructor。但如果有這個需求,記得要把寫好寫滿 constructor(props) 、 super(props) 這樣才可以確保東西都有初始化好。

this

在 React 類組件中的 this 通常指向該類的實例,即指向當前元件的實例。

這意味著可以通過 this 訪問該組件的狀態(state)和屬性(props),以及元件的方法,ex:可以使用 this.setState() 來更新組件的狀態,以及訪問 this.props 來獲取父組件傳遞的屬性。

setState

可以透過this.setState()修改State。

只需要傳入想要更新的 key-value pairs ,React 會自動將傳入和當前State的 key-value pairs 合併 (merge),把新的 key-value paris 會取代掉舊值。

this.setState({ name: "cherry" })

state 的更新是非同步的,因此執行完 setState() 更新 state 後,接著下一行 code,馬上存取 this.state 不一定會拿到最新的值。

setState 還有一個 optional 的第二個參數 callback,callback 是一個 function,用途是當 state 確定已經被更新後,React 就會 call 這個 callback function,讓你可以在 callback 中做些你需要確定 state 已經被更新後才能做的事。

setState(stateChange, callback) // 舉個例子 changeInput(event) { // 會先將值存到text中,再執行後面的validateInput function this.setState({ text: event.target.value }, function() { this.validateInput(); }); } validateInput() { if (this.state.text.length === 0) { this.setState({ inputError: 'Input cannot be blank' }); } }

而setState 也可以接受一個 function 當作參數,該 function 的參數 prevState 是當前最新的 state,而參數 props 是元件當前的 props,在 function 返回一個你要更新的 state 。

// 錯誤寫法 this.setState({ counter: this.state.counter + this.props.increment, }); // 正確寫法 this.setState((prevState, props) => ({ counter: prevState.counter + props.increment }));

Router

傳送門

react-router-dom

react的一個常用套件,可以幫助我們在網頁不刷新的狀況下面做到更新網址,做SPA的時候會需要用到。
現行版本為v6,和v5有蠻大的不同,開發的時候要注意一下。

## 安裝指令
$ npm install react-router-dom

BrowserRouter、HashRouter

以標籤形式包覆SPA最上層的元件,讓元件(包含裡面的子元件)擁有路由的功能

  • BrowserRouter

    • 使用HTML5 history API (pushState, replaceState, popState)
    • BrowserRouter的路徑格式:mypage.com/home
    • 建立在 HTML history API之上,顯示的url簡潔。
      網站上線後,需要有後端配合,接受瀏覽器向這個ur發出的請求,不然會造成連線錯誤。
  • HashRouter

    • 使用URL的hash(window.location.hash)
    • HashRouter的路徑格式:mypage.com/#/home
    • 使用 hash url ,也是就 # 來控制url,瀏覽器不會對的url作出請求。

  • Switch (但v6版本已經沒辦法使用了,改成Routes)
    放在JSX模板的節點內,Switch標籤裡面可以包多個標籤(只能包Route),並控制如果路徑和兩個Route的path都匹配,Switch只會渲染第一個匹配的的Route。

  • Route
    根據路徑渲染對應的Component

    • path:網址後面的後面的路徑。
    • component:此route要顯示的元件。
    • exact:加上exact,url路徑一定要和path完全相同,才會渲染component指定的元件。(例子1)
    • sensitive:url和path的大小寫必須完全相符才會渲染元件。(例子2)
    • strict:搭配exact使用,檢查url的斜線是否也和path完全相同,讓url和path的匹配更嚴謹。
  • Redirect
    重新導向,和Route一樣可以放在Switch標籤之中。

    • to:必要屬性,指定要重新導向的路徑。(例子3)
    • from:from 屬性只有當 Redirect 在 Switch 標籤中和 to 一起時可以使用,當 url 和 from 相符時,便會轉向 to 指定的路徑。(例子4)
    • push:會將重定向的新路徑 Push 至歷史記錄保留,而不是用Replace取代,回到上一頁沒有紀錄。(例子5)
    • 另外:Redirect也和Route一樣有exact、strict、sensitive屬性和from搭配使用,負責檢查url和from的匹配條件。
## 例子1 <Route exact path="/home" component="Home" /> ## 例子2 <Route sensitive path="/Home" component="Home" /> ## 例子3 <Route path='/home' component={Home} /> <Route path='/1' component={One} /> <Redirect to="/home" /> //url如果沒有找到匹配的path就會將頁面導向'/home' //例如:在url輸入'/333'後,url會自動變成'/home'將你導向渲染Home的頁面 ## 例子4 <Switch> <Redirect from='/3' push to="/home" /> <Route path='/home' component={Home} /> <Route path='/1' component={One} /> <Route path='/2' component={Two} /> </Switch> ## 例子5 ```javascript= <Redirect push from='/3' to="/home" />
  • Link
    類似於HTML的a標籤
  • NavLink
    進階的Link,可以根據現在的路由給定Active Style

  • Provider
  • Router
  • RouterApp
## store/index.js import { createStore, applyMiddleware } from 'redux'; import createSagaMiddleware from 'redux-saga'; import { composeWithDevTools } from 'redux-devtools-extension'; import subscription from "./subscription"; import reducers from '../reducers'; import rootSaga from '../sagas'; const sagaMiddleware = createSagaMiddleware(); const store = createStore( reducers, composeWithDevTools( applyMiddleware(sagaMiddleware), ) ); export default store; sagaMiddleware.run(rootSaga); subscription(store);

額外補充

## index.js ReactDOM.render( <Provider store={store}> <Router history={history}> <RouterApp /> </Router> </Provider>, document.getElementById("root") ); # v2 import React from 'react' import ReactDOM from 'react-dom/client' import './index.css' import App from './App' import { BrowserRouter } from 'react-router-dom' const root = ReactDOM.createRoot(document.getElementById('root')) root.render( <BrowserRouter> <App /> </BrowserRouter> )
# route.js(App.js) <EmptyLayout> <HashRouter> <Switch> <Route path="/login" component={LoginScreen} /> <Redirect from="/" to="/login" /> </Switch> </HashRouter> </EmptyLayout> # v2 function App() { return ( <div className='App'> <h1>Hello</h1> <Routes> <Route path='/' element={<Layout />}> <Route index element={<Home />} /> <Route path='about' element={<About />} /> <Route path='dashboard' element={<Dashboard />} /> <Route path='*' element={<NoMatch />} /> </Route> </Routes> </div> ) }
  • <React.StrictMode>
    <Fragment> https://zh-hant.legacy.reactjs.org/docs/fragments.html
    不會渲染任何額外的 DOM 元素。
    用於突出顯示應用程式中的潛在問題。
    啟用嚴格模式
    有時 React 應用程式中的錯誤可能很難追踪,特別是諸如 race conditions 或對元件狀態的不正確假設等細微問題。啟用嚴格模式的額外檢查和警告,您可以在這些錯誤導致嚴重問題之前發現它們。

reportWebVitals.js
為了在單頁應用(SPA)中監控各種重要的網頁效能指標,以便優化性能並提高用戶體驗。