...
function foo(a, b, c, d, e) {
console.log(a, b, c, d, e);
}
var arr = [3, 4];
foo(1, 2, ...arr, 5);
ary1 = [...ary2, ...ary1];
function fun1(...myArgs) {
console.log(myArgs);
}
fun1(); // []
fun1(1); // [1]
fun1(5, 6, 7); // [5, 6, 7]
const arr = ["apple", "banana"];
const [a, b] = arr;
const obj = { fruitOne: "apple", fruitTwo: "banana" };
const { fruitOne: a , fruitTwo: b } = obj;
const [a = 5, b = 7] = [1];
const [a, ...b] = [1, 2, 3];
const str = `first line
second line`;
const age = 23;
function getName() {
return "Alice";
}
console.log(`My name is ${getName()}. I'm ${age > 18? 18 : age} years old.`)
const myPromise = new Promise((resolve, reject) => {
let condition;
if(condition is met) {
resolve('Promise is resolved successfully.');
} else {
reject('Promise is rejected');
}
});
myPromise.then((message) => {
console.log(message);
}).catch((error) => {
console.log(error);
});
import
& export
)export var firstName = "Michael";
export function multiply(x, y) { return x * y; } as MUL;
export class MyClass extends React.Component{...};
// from 後面的 path 可以是絕對或是相對位址
import { foo } from './myApp.js';
import { add, sub } from '/math/utils/myCalculator.js';
import { aVeryLongName as someName } from '../someFile'; // .js 可省略
require: node 和 ES6 都支援
export / import: 只有 ES6 支援
module.exports / exports: 只有 node 支援
import
& export
){ }
export default
則讓我們可以不用管原來檔案裡頭這些 function/class 叫什麼名字,甚至是可以 anonymous// myMath.js
export default (a, b) => a + b;
// index.js
import myAdd from myMath; // myAdd 可以是任意名稱
export default
的 function or class{ }
extends
: 類別繼承super
: 如果子類別 (sub-class) 有定義自己的 constructor,必須在 constructor method 中 call super()
,來調用父類別的 constructor
super()
後,才能引用 this
- framework vs library
- React 只是 V (views) => 只安裝 React 相關套件是不能運作一個完整的前端該有的流程
- 但它有一整套相依的生態系
$ npm install yarn
$ npx create-react-app hello-world
or
$ yarn create react-app hello-world
$ npm init projectName
$ npm install // Babel, webpack, ESLint, etc.,
prepare all scripts for you to run React Apps
hello-world/
README.md
node_modules/ # 各種相依套件
package.json # app 的各種資訊 & 相依套件的版本
public/
index.html # 網頁模版
favicon.ico
src/ # 你的 source code
App.css
App.js # 你的 app
App.test.js
index.css
index.js # JavaScript 進入點
logo.svg
$ cd hello-world
$ npm start (or $ yarn start)
<h1>Hello, world!</h1>
<h1>Hello, wooooorld!</h1>
觀察:存檔之後網頁會自動更新
import React from 'react';
class App extends React.Component {
...
render() {
return <h1>Hello, world!</h1>;
}
}
把網頁的 DOM 想成一個個的 components, 用 JSX 的語法把每個 component 寫成一個 React element,然後利用 React DOM 的 render() method 把 React element 畫到 index.html 對應的節點上面
const element = <h1>Hello, world!</h1>;
{}
放任何合法的 JavaScript expressionconst e1 = <h1> I am a {function(x)} </h1>;
const e2 = <img src={user.avatarUrl} />;
const e3 = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
);
const e4 = (user == "Alice" ? <h1>Hello, {user}!</h1>; <h1> Hello, stranger!</h1>);
// wrong
render() {
return (
<h1>Hello</h1>
<button>World</button>
);
// correct
render() {
return (
<div>
<h1>Hello</h1>
<button>World</button>
</div>
)
}
render() {
return (
<React.Fragment>
<div>Hello</div>
<div>World</div>
</React.Fragment>
)
}
或是
render() {
return (
<>
<div>Hello</div>
<div>World</div>
</>
)
}
class Table extends React.Component {
render() {
return (
<table>
<tr>
<Columns />
</tr>
</table>
);
}
}
class Columns extends React.Component {
render() {
return (
<>
<td>Hello</td>
<td>World</td>
</>
);
}
}
class
-> className
for
-> htmlFor
tableindex
-> tableIndex
參考這裡
- 在 render DOM 之前,會先為目前的 React Element(ReactDOM.render 的第一個參數)建立一個快照(snapshot)
- 以 JavaScript 樹狀結構去仿造 DOM
- 如果並非第一次觸發 render 的話,React 就會比較這次的 Virtual DOM 與上次的 Virtual DOM 的差異(Diff 演算法),並且只會把有差異的部分更新到 DOM 上
index.js
改成如下,點開 devtools 觀察function tick() {
const element = (
<div>
<h1>Hello, world!</h1>
<h2>It is
{new Date().toLocaleTimeString()}.
</h2>
</div>
);
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(element);
}
setInterval(tick, 1000);
通常一個 React app 只會呼叫一次 ReactDOM.render() 而已
props
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
const root = ReactDOM.createRoot(document.getElementById('root'));
const element = <Welcome name="Sara" />;
root.render(element);
React element v.s. React component
- React element 代表實際畫面上的元件,是一個用來模擬 DOM element 的 JavaScript object,且是 React render 時需要的參數
- React component 則代表一個元件的藍圖,可以想成是自定義的 HTML tag name,會是一個 function 或是 class。執行後的 React component 才會產出 React element。
function App() {
return (
<div>
<Welcome name="Monica" />
<Welcome name="Ben" />
</div>
);
}
function AplusB(props) {
if (props.flag)
return <h1> {props.a} + {props.b} = {props.a + props.b}</h1>;
else
return <h1>404</h1>;
}
function App() {
return <AplusB a={2} b={3} flag={true} />;
}
function Welcome(props) {
return <h1>Hello, {props.children}</h1>;
}
const element = (
<Welcome>
<span>Sara</span> // <===
</Welcome>
);
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(element); // <h1>Hello, <span>Sara</span>
props
另一種傳入的方法: { }
function AplusB({a, b, flag}) {
if (flag)
return <h1> {a} + {b} = {a+b}</h1>;
else
return <h1>404</h1>;
}
function App() {
return <AplusB a={2} b={3} flag={true} />;
}
this.props.name = "..."
State
!!props
的參數,並回傳一個 React Elementprops
npm install eslint --save-dev
npx eslint --init
yarn add eslint --dev
yarn run eslint --init
請參考這篇
props
的地方應該會出現 errorERROR in [eslint]
src/components/MyComponent.js
Line 6:35: 'name' is missing in props validation react/prop-types
Line 9:21: 'age' is missing in props validation react/prop-types
MyComponent.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number,
}
或是也可以使用預設值
MyComponent.defaultProps = {
name: "Stranger"
};
有哪些 propTypes 可以參考這裡
/lab/flashcard
pull 下來/src
裡面會有 containers
和 components
,也可以自己新增/public/styles.css
加入style