ttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

The smallest React example looks like this:

  1. ReactDOM.render(
  1. <h1>Hello, world!</h1>,
  1. document.getElementById('root')
  1. );
 

介紹JSX

a syntax extension to JavaScript.

const element = <h1>hello, world</h1>;

這不是string也不是HTML,這是JSX。是JS語法的擴充套件。

用途:在UI和JS程式碼混合工作時,作為視覺化的助手 ;另外,JSX 讓React 顯示很多有用的錯誤和警告資訊。

1.Embedding Expressions in JSX .在JSX中插入JS表示式,用{}括起來。

2.JSX 本身也是Expression.。 可以把JSX用在if,for, 分配給變數,作為引數,和從函式返回。

3.可以用字串作為屬性值,可以用{}插入JS expression給屬性賦值。

const element = <div tabIndex="0"></div>;

const element = <img src={user.avatarUrl}></img>

JSX更像是JavaScript,所以屬性要用駝峰寫法class-> className

4.如果tag是空的,可以用簡寫法:

const element = <img src={user.avatarUrl} />;

5.JSX tags may contain children:就是可以巢狀

const element = (
  <div>
    <h1>Hello!</h1>
    <h2>Good to see you here.</h2>
  </div>
);

6.React.createElement()方法,相等。這個物件稱為 React element.

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!的'
);
const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);

Rendering Elements

React element 是 components的組成部分。

假設有<div id="root"></div>,使用ReactDOM.render操作DOM節點:

const element = <h1>Hello,world!</h1>;
ReactDOM.render(element, document.getElementById('root'));

相當於JS中的document.getElementById("root").innerHTML = element;

React element是惰性的,不能改它的屬性和孩子。

React element只在必要的時候更新:

function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  ReactDOM.render(element, document.getElementById('root'));
}
setInterval(tick, 1000);

因為用setInterval函式每秒呼叫一次tick函式,同時element內部的程式碼new Date(),所以React element元素更新了。


Components and Props

元件比較像JS function,接受輸入( props舞臺道具 )並返回React elements

最簡單定義一個component:使用JS函式。(相對簡潔)

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

這個函式是一個React component,因為它接收了一個props object argument 作為資料並返回一個React element

也可以使用ES6 class來定義一個元件:

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

Rendering a Component

const element = <div />;

這個React element代表Dom tag.⚠️首字母用小寫,程式碼DOM tags.

另外,也可以element也可以代表自定義元件,⚠️首字母用大寫,代表元件。

const element = <Welcome name="Sara" /> ;

當這麼用時,呼叫Welcome元件,並傳遞JSX屬性給這個元件,這個屬性是一個object,稱為object"props",最後返回元件的結果。

例子:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);

過程:

  1. We call ReactDOM.render() with the <Welcome name="Sara" /> element.
  2. React calls the Welcome component with {name: 'Sara'} as the props.
  3. Our Welcome component returns a <h1>Hello, Sara</h1> element as the result.
  4. React DOM efficiently updates the DOM to match <h1>Hello, Sara</h1>.

元件可以在它們的輸出中加入別的元件

例子:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}
function App() {
  return (
    <div>
      <Welcome name="Sara"/>
      <Welcome name="Cahal"/>
      <Welcome name="Edite"/>
    </div>
  );
}
ReactDOM.render(
  <App />,
  document.getElementById('root')
);

Extracting Components

如果一個元件過於複雜,或者一個元件可以在程式中多次使用,那麼可以把它提取出來。類似於Ruby中的dry原則。

Props are Read-Only



State and Lifecycle

State類似於props,但是是私有的,只能被元件控制。

當元件使用class來定義時增加了一些新的features,其中Local state就是其中之一

Converting a Function to a Class

  1. Create an class, with the same name, that extends React.Component.
  2. Add a single empty method to it called render().
  3. Move the body of the function into the render() method.
  4. Replace props with this.props in the render() body.
  5. Delete the remaining empty function declaration.

例子:https://codepen.io/gaearon/pen/zKRGpo?editors=0010

function Clock(props) {
  return(
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {props.data.toLocaleTimeString()}.</h2>
    </div>
  );

function tick() {

ReactDOM.render(

    <Clock data={new Date()}  />,
    document.getElementById('root')
  );
}
setInterval(tick, 1000);

Adding Local State to a Class

3步:

  1. Replace this.props.date with this.state.date in the render() method;
  2. Add a class constructor that assigns the initial this.state:
  constructor(props) {
      super(props);
      this.state = {date: new Date()};
  }

constructor 方法是一個特殊的方法用來創造和初始化一個物件伴隨著一個類。因此這個類中只能有這麼一個constructor方法。

constructor使用super關鍵字來呼叫自己父類的constructor.

3. Remove the date prop from the <Clock />element. 並去掉剩餘函式

結果:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state1 = {data: new Date()};  //就是定義一個變數物件
  }
  
  render() {
    return(
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state1.data.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

Adding Lifecycle Methods to a Class

在元件類中定義特殊的方法componentDidMount(),componentWillUnmount(),當一個元件載入mounting,和解除安裝unmounting時。

這兩個方法叫lifecycle hooks。類似於Ruby中的after_action。鉤子方法。

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }
  
  componentWillUnmount() {
    clearInterval(this.timerID);
  }
  
  tick() {
    this.setState({
      data: new Date()
    });
  }

setInterval(): 每隔指定的時間後,呼叫一次“函式或表示式”。直到clearInterval()被呼叫或者瀏覽器視窗關閉。1000ms =1 second; (詳細解說)

() => {};箭頭函式:arrow function

ES6引用,目的是讓程式碼,更簡短並且不建立自己的this。因為傳統函式一旦新定義就會有自己的this,如果是一個函式巢狀一個新定義的函式,this就會弄混作用域。而箭頭函式不建立自己的this,會使用上下文環境的this值。

(param..) => {statements}

(param..) => expression

//等同(param..) => {return epression; }

//Parenteses are optional when there is only one parameter name:

singleParam => {statements}

//支援引數列表解構

let f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;

f();  // 6

//沒有引數則需要用(), ()=> {}

//Parenthesize the body of function to return an object literal expression:

params => ({foo: bar})

fun.bind(thisArg,..)方法 :

fun執行時,把bind裡的this的值傳給它。fun本身的this的值被替換。

分析:

  1. <Clock />作為引數被傳入ReactDOM.render()後,React呼叫Clock元件的constructor方法。Clock需要顯示當前時間,所以它初始化了this.state,一個包含當前時間的JS物件。之後將更新這個物件,this.state。
  2. 然後,React呼叫Clock元件的render()方法。更新DOM以匹配元件的渲染輸出。
  3. 當元件Clock的輸出插入到網頁對應的DOM後,React 呼叫 lifecycle鉤子方法componentDidMount()。在這個方法內部,元件Clock要瀏覽器建立a timer來每秒呼叫一次元件的tick()方法。
  4. 每秒瀏覽器呼叫tick方法。在tick內部,Clock元件呼叫setState()方法,更新this.state物件中的當前時間。
  5. 由setState()方法,React可以知道this.state已經發生變化,需要再次呼叫render方法。因此瀏覽器頁面上的時間發生變化。
  6. 如果Clock元件要從DOM移走,React呼叫componentWillUnmount()鉤子方法。

⚠️ :在第一次呼叫Clock的人的人方法後,首次載入componentDidmount()方法,從英文名字Did可以看出,元件did後mount。setState和 render一前一後執行。



Handing Evenets處理事件

React events 使用駝峰命名

With JSx you pass a function as the event handler,rather than a string.

兩種方法繫結上下文this:

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};
    // this.handleClick = this.handleClick.bind(this);
  }
  
  handleClick= () => {
    this.setState({isToggleOn: !this.state.isToggleOn})
  }
  
  render() {
    return(
      <button onClick={this.handleClick}>
        {this.state.isToggleOn? 'ON1q' : 'Of1f'}!
      </button>
    );
  }
}
ReactDOM.render(<Toggle />, document.getElementById('root'));

傳遞引數給Event Handlers

二選一:

e引數代表了React event,作為第二個引數。

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>

<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>


條件渲染Conditional Rendering

if 和JS相似;

function UserGreeting(props) {
  return <h1>Welcome back!,{props.name}</h1>;
}
function GuestGreeting(props) {
  return <h1>Please sign up.</h1>;
}
function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if ( isLoggedIn) {
    return <UserGreeting name="chentianwei"/>;
  } else {
    return <GuestGreeting />;
  }
}
ReactDOM.render(
  <Greeting isLoggedIn="true" />,
  document.getElementById('root')
);

反覆練習:

全的案例:https://codepen.io/gaearon/pen/QKzAgB?editors=0010

程式碼少但是功能都有:https://codepen.io/gaearon/pen/Xjoqwm?editors=0010

this.handleLoginClick = this.handleLoginClick.bind(this); 為啥要這麼繫結?
函式宣告會自帶this,這個this不是上下文的this,要用到上下文環境的this,就需要bind(this);另外可以用箭頭函式,因為箭頭函式自動繫結上下文this。

handleLoginClick = () => {}


List and Keys

Basic List Component:

  const numbers = props.numbers
  //使用map方法遍歷陣列。
  const listItems = numbers.map((number) =>
    <li>{number}</li>
  );
  return(<ul>{listItems}</ul>);                     
}                                          
const numbers =[1,2,9];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

這組程式碼在嚴格模式下Console會彈出⚠️,

  1. "Warning: Each child in an array or iterator should have a unique 'key' prop. 

因為<li> 沒有加上key關鍵字,類似於id。唯一識別碼,用於改變和增減。

改為: <li key={number.toString()}>,⚠️key應該是唯一的,這裡是唯一的。

規則:在map()裡的element加上key.

規則:最好的key是唯一的識別碼 ,在同等級的Siblings中。


Forms

HTMl from elements有自然的內部state,它有預設的behavior提交表格時定位到新的頁面。React也支援這個行為,但是如果用JS function來處理表格的提交和存取資料會非常convenitent。 這種實現技術稱為 controlled components.

Controlled Components

在HTML如<input> <textarea> <select>基於使用者的輸入來儲存或更新它們的state。在React, 易變的state儲存在元件的state property中,更新則使用setState().

案例:https://codepen.io/gaearon/pen/VmmPgp?editors=0010

疑問:

1.event.target.value是什麼意思?

event是一個虛擬的事件。React定義這些synthetic events用來對應 W3C(event)標準。

個人理解:DOMEventTarget target

這是SyntheticEvent object的attributes >見擴充套件,每個物件有14個屬性(其中4個方法)。

擴充套件:SyntheticEvent: https://reactjs.org/docs/events.html

我們的事件處理會被傳到SyntheticEvent的例項,一個關於瀏覽器原生事件的跨瀏覽器包裹器wrapper。和原生瀏覽器事件的互動是一樣的,包括stopPropagation()和preventDefault().

2.event.prevetnDefault();

答案:這也是SyntheticEvent例項物件的屬性,一個方法,React不能使用 return false來防止預設的行為,如防止預設開啟一個link到新的網頁。因此必須使用preventDefault();

<a href="#" onclick="console.log('The link was clicked.'); return false">
    Click me
</a>

一個控制的元件,每個state都關聯一個處理函式,因此可以修改或驗證使用者輸入。例如,讓輸入的名字強制轉化為大寫字母。

handleChange(event) {
  this.setState({value: event.target.value.toUpperCase()});
}

Textarea tag

In HTML, a <textarea> element defines its text by its children.一般是firstChild。因為在HTML DOM中,text,attribute都是節點。

而在React中,text則被當做a value attribute處理。在constructor可以初始化這個value。


Select Tag
IN HTML

<select>
  <option value="grapefruit">Grapefruit</option>
  <option value="lime">Lime</option>
  <option selected value="coconut">Coconut</option>
  <option value="mango">Mango</option>
</select>

而在React中,則constructor初始化這個預設選項。this.state = {value: 'coconut'};

⚠️ :select接受array傳入value屬性 <select multiple={true} value={['B', 'C']}>

一句話,<input type="text">. <textarea> <select>都接受a value attribute.


練習程式碼:https://codepen.io/gaearon/pen/JbbEzX?editors=0010

  1. 一類元素對應一個觸發的方法。最好不要寫一起,不易讀。如select,和textarea的onChage={}應該分別寫不同的方法。偏要寫一起的話,使用name進行區分。
  2. preventDefault();必須得有,否則回到預設頁面。
  3. 不要瞎嘗試,看現成的案例,或找相關文件。下午耽誤了不到一個小時,就是因為在select和textarea元素的屬性上不清楚,竟然想自定義屬性?!!
class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2,
      selectValue: "chen",
      textarea: "Hello,"
    };
    this.handleInputChange = this.handleInputChange.bind(this);
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  
  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;
    this.setState({
      [name]: value    //必須加【】,這是ES6新寫法
    });
  }
  
  handleChange(event) {
    const target = event.target;
    this.setState({
      [name]: target.value
    });
  }
  
  handleSubmit(event) {
    alert(this.state.textarea + "" + this.state.numberOfGuests + "" + this.state.selectValue);
    event.preventDefault();
  }
  
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Is going:
          <input name="isGoing" type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          Number of guests:
          <input name="numberOfGuests" type='number'
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange}/>
        </label>
        <br />
        <label>
          textarea:
          <textarea name="textarea" value={this.state.textarea} onChange={this.handleChange}/>
          <select name="theName" value={this.state.selectValue} onChange={this.handleChange}>
            <option value="No1">chen</option>
            <option value="No2">tian</option>
            <option value="No3">wei</option>
          </select>
          <input type="submit" value="Submitx" />
        </label> 
      </form>
    )
  }
}
ReactDOM.render(
  <Reservation />,
  document.getElementById('root')
);

Lifting State up :

把狀態放到作為祖先的元件中,子元件則可以共享這個state了。 這麼做的目的:多個元件共用一個相同的變化的資料。即:lifting the shared state up to their closest common ancestor。

首先, 把TemperatureInput中的state移動到Calculator中。讓它成為兩個TemperatureInput例項的source of truth 。如此input會同步變化。

第一,把this.state.temperature 替換為this.props.temperature。props來自Calculator。

因為props是隻讀的,同時來自父類,所以TemperatureInput不能直接控制它。

解決辦法是讓元件可控,即讓TemperatureInput從父元件接收除了溫度props外還有溫  度的控制方法onTemperatureChange props。

  handleChange(e) {
    // Before: this.setState({temperature: e.target.value});
    this.props.onTemperatureChange(e.target.value);
    // ...

第二,在render()中,const temperature = this.props.temperature;

然後,設計Calculator元件。

state為temperature和 scale單位符號。這就是lifted up的state。它作為source of true 服務於所有子元件。

本例中,只要儲存一個格式的資料即可,另一個格式隨時通過換算來顯示結果。

增加處理Celsius和Fahrenheit的方法,用於設定setState.

在render(){}中進行celsius和fahrenheit的資料計算。

在return()中,呼叫TempertureInput元件兩次,分別傳入state,和控制方法。

總結: recap

  1. React calls the function specified as onChange on the DOM <input>。本例就是在溫度輸入元件TemperatureInput中的handleChange() 方法.
  2. handleChange方法使用this.props.onTemperatureChange(),props來自父元件Calculator。
  3. 父元件指定了傳入的props中的方法是F還是C。傳入哪個方法依據我們輸入input的位置。
  4. 在這些方法中,父元件因為呼叫this.setState()更新state,所以會再渲染。
  5. React呼叫父元件的render方法內部,兩種格式的溫度會再計算。
  6. 然後渲染方法會return 2個不同scale,temperature及其控制方法的TemperatureInput元件。
  7. React Dom更新DOM來匹配輸入的值。我們剛才輸入值的input框得到它當前的值,另以一個input框更新轉換的溫度值。
top->down data flow
可以把元件樹看成黃河,每個元件的state作為一個支流水源加入。每個子元件都可以使用父元件及祖先們傳入的state資料。

每個元件都是獨立的,都可以繼承一個父元件的完整state。

parseFloat(string)方法,把string-> 浮點數。

parseInt(string) 轉化為整數。

Number.isNaN(),當算數運算返回一個為定義的或無法表示的值時,NaN就產生了。

React Developer Tools用於檢查資料有chrome, Safari等主流版本。

codepen中使用他人的程式碼,先fork再選擇Change View > Debug。就可以使用了。

const output = convert(input); convert是傳進來的函式。

const rounded = Math.round(output *1000)/1000?

Math.round(x),返回給定數字的值四捨五入到最接近的整數。乘以1000是為了保留小數。


Composition vs Inheritance

React有強大的組成模組,因此建議程式設計師多用Composition而不是繼承。類似Ruby  min-in model 。

在Facebook中使用了上千的components,沒有用到元件繼承。

Props and composition可以靈活的客製化一個元件的外觀和行為。 因為元件可以接收各種各樣的props,包括原始的value, React element, function.

Containment:

一些元件事先不知道它們的children。因此可以使用特殊的props: {props.children }去傳遞children elements  然後直接進入它們的輸出。

function FancyBorder(props) {
  return (
    <div className={'FancyBorder FancyBorder-' + props.color}>
      {props.children}
    </div>
  );
}

任何在<FancyBorder>JSX tag內的元素, 作為props.children被傳遞給FancyBorder元件。

也可以客製化傳入,如下例子:

function App() {
  return (
    <SplitPane
      left={
        <div className="Contacts" />
      }
      right={
        <Chat />
      } />
  );
}

然後在SpliPane元件中插入{props.left}和{props.right}

全程式碼:

https://codepen.io/chentianwei411/pen/QrbXeq?editors=0010

Specialization

有時把某個元件當成特殊的某個元件。Ruby, 動物類包含有哺乳類,鳥類。

https://codepen.io/gaearon/pen/kkEaOZ?editors=0010

類似於繼承。元件FancyBorder繼承了Dialog中的屬性title,message

composition 也可以在class定義的元件中工作得很好。

https://codepen.io/gaearon/pen/gwZbYa?editors=0010

在ES6中,${}用來代替引號拼接。類似Ruby中的插入#{}。

alert("welcome," + this.state.login );

alert(`welcome, + ${this.state.login}`)  ⚠️ 是`, 單引號和雙引號不行。



例項:用React設計一個小的功能:

在React中有兩類model data:props and state:

我的理解:props是元件之間資料,格式,函式等任何資料的傳遞,state是一個元件的定義的屬性。 可以用props傳遞state。

Step1:Break the UI into Component 層

首先是分析需求,用畫圖來幫助思考的行為。給每個元件起名字要適合它們的特點。

根據單一責任原理,一個元件理論上只做一件事情。隨著元件的成長,應該把它拆分為更小的子元件。

FilterableProductTable

  • SearchBar
  • ProductTable

    • ProductCategoryRow
    • ProductRow
Step2: Build A static version in react

先把架子搭起來。整體的層次hi.er.archy。

最簡潔的方法:先建立一個包括data model和render UI但沒有互動行為的版本。

因為建立一個靜態版本只需大量的type不需要思考,而互動設計則需要大量思考而type較少。

⚠️ state是為互動行為服務的,建立靜態版本無需使用state.

為了建立一個靜態版本的app,需要渲染資料模組,renders your data model。

應當建立那種可以反覆使用其他的元件和使用props傳遞data的元件。

props是把資料從父傳給子的一個辦法。

選擇建設元件的方式:

小的app:設計原則是從top->down,  大的複雜的app則相反bottom-up。

最後,用reusable的元件渲染你的資料model。作為靜態版本,元件中只有render()方法。

FilterableProductTable元件處於the top of the hierarchy, 它用props傳遞data model。

forEach方法

mySet.forEach(function callback(value1, value2, Set){

//your iterator

}[, thisArg])

callback: Function to execute for each element

value1,value2: The value contained in the current position in the Set.

當set物件no key時,value2也是值。這樣Array也可以使用forEach方法。

set: The set object that's being traversed.

thisArg: Value to use as this when executing callback

對集合中的每個原素執行提供的callback函式一次,它不返回任何值。

用到了關鍵字key.

Step3: Identify the minimal(but complete)Representation of UI State 識別最小的UI state

為了正確建立app,首先,思考哪些是最小變化的state。這裡也提出dry 原則。

找出絕對的代表最小state。

本例:

  • 原始的產品列表
  • 使用者輸入的搜尋文字
  • checkbook的值
  • 產品檢索後的列表

思考:找出state。問3個問題:

  1. Is it passed in from a parent via props? If so, it isn't state. (存在於層次較高的元件)
  2. Does it remain unchanged over time? If so, it isn't state. (值肯定是會改變)
  3. Can you compute it based on any other state or props in you component? If so, it isn't state.(不會參與其他state/props的計算)
分析一下,原始產品列表是作為props的,所以不是state。使用者輸入框和checkbox會變化但不參與計算,所以是state。最後檢索後的列表不是state,因為它是被計算得到的資料(通過原始資料和搜尋文字和checkbox計算後得到的資料)

最後,我的的state是:

The search text that user has entered, the value of the checkbox

Step4: Identify where your state should live

識別這些state存在於哪個元件。

記住:React是關於單向資料流動的元件層級關係。對應新手來說,不容易理解元件應該擁有什麼state。所以跟隨以下思考步驟:

  • 識別每個元件基於state渲染了什麼。
  • 找到一個共同的擁有者元件,在層級上比其他元件更高的元件需要state。
  • 在層級上更高的元件應當擁有state.
  • 如果不能找到一個元件讓它適合擁有一個state, 則建立一個新的元件來持有這個state並且這個新元件在層級上應該高於這個普通元件。
根據這些原則:來分析本案例。
  • ProductTable 擁有檢索產品列表(基於state和SearchBar)
  • The common owner 元件 是 FilterableProductTable
  • 檢索文體和checked 值在FilterableProductTable中是可以的
所以,我們決定了state放在FilterableProductTable 。

首先:增加一個例項特性instance property this.state={filterText: '', inStockOnly: false}

其次:傳遞filterText和inStockOnly給ProductTable 和 SearchBar作為一個prop.

最後:使用這些props來檢索在ProductTable中的Rows

indexOf(searchElement[, fromIndex]) :

returns the first index at which a given element can be found in the string/array, or -1 if it is not present.

indexOf()方法返回呼叫String/Array物件中第一次出現的指定值的索引,如果沒有找到則返回-1.⚠️indexOf是用嚴格模式,區分大小寫字母。如:

"Blue Whale".indexOf("blue")    //returns -1

Array.indexOf():例子

var beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];
console.log(beasts.indexOf('bison')); 輸出1

console.log(beasts.indexOf('bison', 2));  輸出4 ,fromIndex開始搜尋的位置,如果這個索引大於等於陣列的長度,返回-1

console.log(beasts.indexOf('giraffe'));  輸出-1

String.indexOf():例子:

var str = "To be, or not to be, that is the question.";

var count = 0;

var pos = str.indexOf('e');  // 相當於Ruby中的 index方法,Ruby沒有找到返回nil。

while (pos !==-1 ) {

count++;

pos = str.indexOf('e', pos + 1);

}

console.log(count); //display 4


Step5: Add Inverse Data Flow

第4步,當函式的props和state順著元件的層級hierarchy向下流動時,app正確地渲染。

現在,到了支援資料逆向流動的步驟。表格元件需要更新FilterableProductTable中的state。

當用戶改變form時,我們根據使用者的輸入input更新state。元件只能更新自己的state。所以FilterableProductTable會把更新的回撥行為傳給SearchBar。我們使用onChange事件。這個由FilterableProductTable傳遞的回撥行為叫做setState. 之後app就會更新state了,之後則是因為state的改變,導致state data沿著元件的層級順流而下,app渲染各個元件。

看起來複雜,但程式碼只有幾行。並且這種清晰的資料流動遍及整個app。

❌:上層元件傳遞的對state操作的方法的name,不能和傳入的元件中宣告的方法同名,這樣會造成控制組件中的某個輸入功能無效。本例子:

傳入的名字:handleInStock,元件中自身也在constructor中命名一個handleInStock自然會無效。

⚠️ :return關鍵字在Ruby和JavaScript中的理解。

Ruby中return可以用於結束當前迴圈並返回值 (當然還有別的地方也用return),而在JS中return用於結束函式執行並返回一個指定值,箭頭函式也是函式。

記住:程式碼是用來讀的而不是寫的。就是可讀行,可理解行強。清楚的模組很容易讀和理解。

當建立大的app的元件時,每個功能都用獨立的元件,因為會反覆使用元件,所以整體上程式碼會shrink收縮。