gracekrcx / weekly-notes

4 stars 0 forks source link

[2020-02-10] React #60

Open gracekrcx opened 4 years ago

gracekrcx commented 4 years ago

React 是什麼?

React is a JavaScript library for building user interfaces. 負責 building 使用介面。 方便 building 出 UI 的一個 JavaScript library

  1. 用 component 的角度來思考 UI
  2. UI 只是狀態(state)的呈現
  3. Client side rendering,用 JavaScript 產生 HTML img

預備知識

重要概念

JSX

  1. 在 html 裡加入 { javascript 程式碼 }
    <div>{javascript}</div>
    <div><? echo test ?></div>   // 類似 php

Single Page Application

  1. 從頭到尾都只有在一個 Page 上
  2. 只有最原始的 html 是從 Server 拿的,其他的都是在 client 用 ajax 取得,再利用 JS 渲染出來 ,所以使用者完全感覺不到「換頁」
  3. 像在電腦上用 APP
  4. 缺點:所有事情都變成要 client side 來做

state 的值是 array 或 object 時


constructor(){
 super()
 this.state={
  list:[1,2,3]
 }
}
// 下面這樣可以嗎?
handleClick = ()=>{
 const newArr = this.state.list
 newArr.push(123)
 this.setState({
  list: newArr 
 })
}

// 使用 es6 語法
handleClick = ()=>{
 this.setState({
  list: [...this.state.list, 123] 
  //  [...this.state.list, 123] ===  this.state.list => false  
  // 這樣 react 才會知道你更新了 
  // 重點:要有一個新的記憶體位置 
 })
}

惱人的 this 又來了

document.querySelector('button').addEventListner('click', function(){
 console.log(this)  // 這個 this 會是上一行的 button
})

class App extend componenrt {
 constructor(){
  super()
 }
 handleClick(){
  alert(this.state.count)  
  // 這個 this 應該會是下方的 button
  // 但如果實際 console.log 會是 undefined  
  // 但一定不是 App 這個 componenrt
 }

 render(){
  return(
   <div>
    <button onClick={this.handleClick}></button>
   </div>
  )
 }
}
// ---> 解決方法 1 : 加上 bind
class App extend componenrt {
 constructor(props){
  super(props)
  // 加上 bind
  this.handleClick = this.handleClick.bind(this) // 這裡的 this 是 App 這個 component 
 }
 handleClick(){
  console.log(this)  // 這時候這裡的 this 也是 App 這個 component 了
 }

 render(){
  return(
   <div>
    <button onClick={this.handleClick}></button>
   </div>
  )
 }
}
// ---> 解決方法 2 : Class Properties 
class App extend componenrt {
 constructor(){
  super()
 }

 handleClick = () => {
  console.log(this)  // 這時候這裡的 this 也是 App 這個 component 了
 }

 render(){
  return(
   <div>
    <button onClick={this.handleClick}></button>
   </div>
  )
 }
}
// ---> 解決方法 3 : Bind in Render 
class App extend componenrt {
 constructor(){
  super()
 }

 handleClick = () => {
  console.log(this)  // 這時候這裡的 this 也是 App 這個 component 了
 }

 render(){
  return(
   <div>
    <button onClick={this.handleClick.bind(this)}></button>
   </div>
  )
 }
}

class App extend componenrt {
 constructor(){
  super()
  this.handleClick = this.handleClick.bind(123) 
  this.handleClick = this.handleClick.bind('abcabc') 
 }
 handleClick(){
   // 上面 bind 什麼東西,這裡就會出現什麼,強制綁定 this 的值
  console.log(this)  // 123
  console.log(this)  // 'abcabc'
 }
}

create react app

把事切開看,這個功能是因為這個,跟什麼沒關係,講的很清楚,我喜歡

  1. npm run dev 是執行 webpack-dev-server,執行開發模式,也一併處理 hard reload (websocket),所以如果你不要 hard reload,就不需要 webpack-dev-server

  2. react 跑在前端跟 server 沒有任何關係,這句一開始不懂,因為操作上我們都是 npm run dev 然後 localhost:3000,怎麼會說沒有關係,但當 npm run build 然後把 script 的 link 改成相對路徑之後,好像就懂老師的意思了

  3. 如果不需要 hard reload,又想看修改後的結果,那用 pm run build 一樣可以看到,pm run build 是用 webpack 把檔案打包成 js 檔,但如果你直接打開 build/index.html 會看到空白,打開 console 可以看到原因,因為預設檔案是要放在 server 上存取,所以輸出是用絕對路徑。如果一定要在這個資料夾底下打開絕對路徑的檔案,可以在資料夾起一個 server,指令:python -m SimpleHTTPServer 8111,所以一開始會看到空白頁面,是因為路徑有問題需要調整,也可以進去打包好的 js 檔把絕對路徑改成相對路徑,一樣可以打開畫面

    href='./static/css/main.123456.chunk.css'
  4. 或是在 package.json 裡加一個設定

    homepage:"."
  5. 把 build 資料夾裡的東西丟到 server 就 ok 了

img

create react app 的 build

code splitting webpack 有機會看看 img

create react app 的 webpack config and files?

link

Client side render vs Server side render

Client side render : 在 client side 渲染出來,在 client 端拿資料然後用 javaScript 動態產生HTML 檔 Server side render: 在 server 端就產生了內容,在 server 端拿資料,產生 HTML 檔,並把整個 HTML 檔傳回 client

參考文章

從零開始學 ReactJS 解決React重複渲染效能問題

gracekrcx commented 4 years ago

testHandle = () => console.log('hello') testHandle2 = (a) => console.log(a)

// JSX
<button onClick={ this.testHandle }></button>
<button onClick={ ()=>this.testHandle2(11) }></button>
<button onClick={ function(){this.testHandle2(11)} }></button>
document.querySelector(‘body’).addEventListener(‘click’, () => { testHandle2(11) })
document.querySelector(‘body’).addEventListener(‘click’, function () { testHandle2(11) } )
gracekrcx commented 4 years ago

官網介紹 JSX

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

不是一個字串也不是 HTML。這個語法叫做 JSX

為什麼要用 JSX?

  1. 一個 component 裡包含
    • 事件
    • 隨著時間經過的 state
  2. React 關注點分離(Separation of concerns)的方法,是將其拆分為很多同時包含 UI 與邏輯的 component,而彼此之間很少互相依賴。 -> 小結:或許白話一點,邏輯原本就是用 js 寫,但現在因為希望 UI 與邏輯可以共同存在 component 裡,所以使用 JSX,用 js 寫 html,或是說回傳 js object 去 render DOM,主要目的就是希望全部都 js 就對了(誤...)

在 JSX 中嵌入 Expression

  1. 可以在 JSX 的大括號中寫入任何合法的 JavaScript expression。 舉例來說,底下都是合法的 JavaScript expression。 (1) 運算:2 + 2 (2) 變數:user.firstName (3) function call:formatName(user)
function formatName(user) {
  return user.firstName;
}

const element = (
  <h1>
    Hello, {formatName('Tom')}   // function 直接呼叫,馬上 render Tom 在 DOM 上
  </h1>
);

ReactDOM.render(
  element,
  document.getElementById('root')
);

JSX 本身也是 Expression

重點!重點! 在編譯之後,JSX expressions 就變成了一般的 JavaScript function 呼叫並回傳 JavaScript 物件。 Babel 將 JSX 編譯為呼叫 React.createElement() 的程式。 然後回傳類似下面的物件,這種物件被稱呼為「React element」:

// 注意:這是簡化過的結構
const element = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world!'
  }
};

所以可以在 if 跟 for 迴圈中使用 JSX

function getGreeting(user) {
  if (user) {
    return <h1>Hello, {formatName(user)}!</h1>;
  }
  return <h1>Hello, Stranger.</h1>;
}

在 JSX 中指定屬性

JSX 比較接近 JavaScript 而不是 HTML

// 字串設定為屬性
const element = <div tabIndex="0"></div>;

// 在屬性中使用大括號來嵌入一個 JavaScript expression
const element = <img src={user.avatarUrl}></img>;

底下文章解釋: But let's explore why we should not call a React function component. React Element vs Component

gracekrcx commented 4 years ago

關注點分離(Separation of concerns,SoC)

關注點:「特定概念、特定目標」

由於關注點混雜在一起會導致複雜性大大增加,所以能夠把不同的關注點分離開來,分別處理就是處理複雜性的一個原則。

關注點分離,就是將交錯著各種目的的複雜程式碼,依程式碼的概念、目的,進行分類、篩檢、整理。讓高複雜性程式碼切割、轉換為簡潔易懂的單純性程式碼。

16. 常見軟體架構之一 - MVC (待補完)

gracekrcx commented 4 years ago

為什麼需要 bind(this)

當使用 extend React.Component 的方式去宣告元件的時候,React 確實會綁定 this 到元件內,但是卻有以下特定的地方才會被綁進去

  1. 生命周期函式,例如 componentDidMount 等等
  2. render 內

其他自己定義的 property 就不會被綁入 this ,而且 this 會被指到 windows 這個全域上。

React 與 bind this 的一些心得

gracekrcx commented 4 years ago

npm start 做了些什麼

1. webpack 做了什麼?

webpack-dev-middleware 和 webpack-hot-server-middle 作為開發環境的工具(把 ./static/bundle.js 存到 memory), 當 Component 有所改變時也同時改變 ./static/bundle.js 的內容, 使得瀏覽器即看更新程式的變化。

2. express 做了什麼?

Express server 作為 HTTP server

3. 藍色方格是Isomorphic的精華部份 React/Redux

裡面處理了 react component, redux, root component, store 和 reducer 的所有互動。

img 深入淺出: Isomorphic 的核心架構: React-Redux Server Rendering