[乾貨]一篇筆記入門React

我的筆記, 轉載請註明html

轉載自 szhshp的第三邊境研究所react

Refs and the DOM

In the typical React dataflow, props are the only way that parent components interact with their children. To modify a child, you re-render it with new props. However, there are a few cases where you need to imperatively modify a child outside of the typical dataflow. The child to be modified could be an instance of a React component, or it could be a DOM element. For both of these cases, React provides an escape hatch.git

通常狀況下想要刷新child elem必須經過新的prop刷新, 可是其實能夠有另外一個方法, 就是使用refgithub

When to Use Refs

There are a few good use cases for refs:express

  • Managing focus, text selection, or media playback.
  • Triggering imperative animations.
  • Integrating with third-party DOM libraries.

Avoid using refs for anything that can be done declaratively.api

For example, instead of exposing open() and close()methods on a Dialog component, pass an isOpen prop to it.數組

使用ref以前切記要肯定一下對應的屬性是否是可使用prop代替, 開發時應該儘量聽從React推薦的信息流閉包

Adding a Ref to a DOM Element

React supports a special attribute that you can attach to any component. The ref attribute takes a callback function, and the callback will be executed immediately after the component is mounted or unmounted.app

關於ref有這些特色:less

  1. 能夠給任何DOM提供這個attr
  2. 提供給ref的value應該是個callback
  3. 這個callback能夠在mounted/unmounted的時候調用
  • 注意會在mounted/unmounted的時候執行一次, 而不是每次渲染的時候執行
  1. 當提供這個參數給HTML elem的時候, 這個ref指向的callback會獲取當前DOM elem做爲參數.

例子:

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.focusTextInput = this.focusTextInput.bind(this);
  }

  focusTextInput() {
    // Explicitly focus the text input using the raw DOM API
    // 3. 所以這兒能夠經過this.textInput調用focus()方法
    this.textInput.focus();
  }

  render() {
  
    // Use the `ref` callback to store a reference to the text input DOM
    // element in an instance field (for example, this.textInput).
    // 1. Component載入的時候就會執行ref裏面的callback.
    // 2. 而後這個Elem會當作參數傳入, 所以就能夠經過this.textInput引用這個DOM elem
    
    
    return (
      <div>
        <input
          type="text"
          ref={(input) => { this.textInput = input; }} />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focusTextInput}
        />
      </div>
    );
  }
}

Adding a Ref to a Class Component

相似ref在HTML DOM中的使用, 將ref賦值給自定義Component的時候, ref對應的callback就會接受自身這個instance做爲參數

注意: 必需要這個自定義Component是個完整的class, 不能夠是函數

When the ref attribute is used on a custom component declared as a class, the ref callback receives the mounted instance of the component as its argument. For example, if we wanted to wrap the CustomTextInput above to simulate it being clicked immediately after mounting:

class AutoFocusTextInput extends React.Component {
  componentDidMount() {
    // 2. 這兒就能夠對這個instance進行引用
    this.textInput.focusTextInput();
  }

  render() {
    return (
      <CustomTextInput
      // 1. 對於自定義的Component, ref對應的callback會將自身這個instance當作參數傳進去
        ref={(input) => { this.textInput = input; }} />
    );
  }
}

Exposing DOM Refs to Parent Components

通常數據流不該該在Parent Class裏面控制Child Class, 可是偶爾就有這樣傻逼的需求.

這時候用ref最適合了, 可是依然不推薦這麼使用.

更好的解決辦法是你和需求分析的人打一架而後讓他根據代碼改需求

固然上文提到了解決辦法是讓child class暴露一個prop, 可是這個辦法沒法對function Component使用.

另外下面這個辦法對function Component也有用:

function CustomTextInput(props) {
  // 2. 在child component裏面將這個callback賦值給ref
  // 2+. 固然這兒只能用ref這個attr
  // 3. 而後這個child component在mount/unmount的時候就會執行這個callback
  return (
    <div>
      <input ref={props.inputRef} />
    </div>
  );
}

class Parent extends React.Component {
  render() {
  // `Parent` passes its ref callback as an `inputRef`prop to the `CustomTextInput`
  // 1. 這兒提供一個callback做爲props.inputReg
    return (
      <CustomTextInput
        inputRef={el => this.inputElement = el}
      />
    );
  }
}

最終在parent component中就能夠經過inputElement這個變量調用到對應輸入框元素.

並且這個能夠逐級傳遞, 好比下面這個隔代傳遞的例子:

function CustomTextInput(props) {
  return (
    <div>
      <input ref={props.inputRef} />
    </div>
  );
}

function Parent(props) {
  return (
    <div>
      My input: <CustomTextInput inputRef={props.inputRef} />
    </div>    
  );
}

class Grandparent extends React.Component {
  render() {
    return (
      <Parent
        inputRef={el => this.inputElement = el}
      />
    );
  }
}

看起來暴露DOM有些彆扭, 可是不少時候需求就是比較特別. 所以上面是推薦用法.

舊版本React裏面曾經有過使用this.refs.textInput的用法, 其中ref會指向一段字符串, 新版本React不推薦如此使用

注意事項

若是ref是個inline function, updates的時候會被調用兩次. 第一次是null而後第二次是DOM Elem.

這個是由於update的時候React須要清理舊的而且創建新的component

Solutions

爲了防止這個問題, 能夠將ref callback和對應class進行綁定.

即便不綁定也不會引起太多問題

JSX In Depth

JSX將經過Babel進行編譯.

標準首位標籤格式

<MyButton color="blue" shadowSize={2}>
  Click Me
</MyButton>

compiles into:

React.createElement(
  MyButton,
  {color: 'blue', shadowSize: 2},
  'Click Me'
)

自閉合標籤格式

You can also use the self-closing form of the tag if there are no children. So:

<div className="sidebar" />

compiles into:

React.createElement(
  'div',
  {className: 'sidebar'},
  null
)

Specifying The React Element Type

通常Component使用大寫字母開頭, 若是在當前JSX裏面使用<XXX/>那麼XXX這個Component就必須出如今Scope以內.

另外可使用import語句將Component引用到Scope內

Using Dot Notation for JSX Type

import React from 'react';

const MyComponents = {
  DatePicker: function DatePicker(props) {
    return <div>Imagine a {props.color} datepicker here.</div>;
  }
}

//下方使用圓點標識符調用了子屬性
function BlueDatePicker() {
  return <MyComponents.DatePicker color="blue" />; 
}

User-Defined Components Must Be Capitalized

自定義Component(好比 <MyComponent/>)應該大寫字母開頭
系統自帶的Component(好比 <div/>)應該小寫字母開頭

不然系統會拋出警告

Choosing the Type at Runtime

注意JSX Obj的tags必須是完整的單詞, 若是想要動態生成tag名稱能夠用賦值的辦法

錯誤的例子:

function Story(props) {
  // Wrong! JSX type can't be an expression.
  return <components[props.storyType] story={props.story} />;
}

正確的作法:

function Story(props) {
  // Correct! JSX type can be a capitalized variable.
  const SpecificStory = components[props.storyType];
  return <SpecificStory story={props.story} />;
}

Prop in JSX

JavaScript Expressions as Props

關於使用JS表達式做爲prop:

<MyComponent foo={1 + 2 + 3 + 4} />

If condition within JSX

不可以直接使用, 可是能夠用這個替代方法:

function NumberDescriber(props) {
  let description;
  
  // check the condition
  if (props.number % 2 == 0) {
    description = <strong>even</strong>;
  } else {
    description = <i>odd</i>;
  }
  
  
  return <div>{props.number} is an {description} number</div>;
  
  
}

另一個很實用的條件判斷的snippet

This can be useful to conditionally render React elements. This JSX only renders a <Header /> if showHeader is true:

<div>
{showHeader && <Header />}
<Content />
</div>

### String Literals


When you pass a string literal, its value is HTML-unescaped. So these two JSX expressions are equivalent:



<MyComponent message="<3" />

<MyComponent message={'<3'} />

### Props Default to 「True」


If you pass no value for a prop, it defaults to true. These two JSX expressions are equivalent:

<MyTextBox autocomplete />

<MyTextBox autocomplete={true} />

### Spread Attributes


If you already have `props` as an object, and you want to pass it in JSX, you can use `...` as a 「spread」 operator to pass the whole props object. These two components are equivalent:

>提供Props時, 如有一個Obj而且這個Obj裏面全部Attr和須要的Prop相匹配, 那麼可使用`spread` operator 進行賦值


function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}

function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}

另外對於`spread` operator也能夠給部分值賦值:



const Button = props => {

//將傳進函數裏面的props.kind 賦值給kind, 將其餘屬性賦值給...other
const { kind, ...other } = props;

const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
//而後將...other傳給button這個elem, 而沒有傳遞kind這個參數
return <button className={className} {...other} />;
};

const App = () => {
return (
<div>
<Button kind="primary" onClick={() => console.log("clicked!")}>
Hello World!
</Button>
</div>
);
};

> # 關於解構運算符
>
>MDN參考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator
>
這玩意是ES6新引進的運算符, 經過三個點進行引用`...`
>
> ```
>function sum(x,y,z){
  return x+y+z
}
>
console.log(sum(...[1,2,3])) //6
console.log(sum(...[1,2,3,4,5])) //6
console.log(sum(...[1,,3,4,5])) //NaN
>
var doSomething = function(...args){
  return sum(..args)
}
>
console.log(doSomething(...[1,2,3])) //6
>
//對Object是否有效呢?
var obj = { a:"A", b:"B", c:"C", d:"D", e:"E" }
var {a,b,...others} = obj //報錯var {a,b,...others} = obj //報錯

在老版本ES6中, 對Obj進行解構賦值會報錯, 可是JSX中容許這樣的使用.

Children in JSX

子元素所有會經過props.children進行引用.

另外若是沒有子tag而只是放置了一段文本, 那麼props.children就會是tag之間的一段字符串

Hint: HTML is unescaped!

<MyComponent>Hello world!</MyComponent>

<div>This is valid HTML &amp; JSX at the same time.</div>


tags之間的空格和空行都會被忽略.

<div>

  Hello World
</div>

另外也能夠將JS表達式用於child elem. 好比一個很典型的使用數組循環生成列表的例子:

  return (
    <ul>
      {todos.map((message) => <Item key={message} message={message} />)}
    </ul>
  );

Functions as Children

反正只要最後返回的是一個完整的JSX Obj便可

// 2. 咱們在渲染parent elem
function Repeat(props) {
  let items = [];
  for (let i = 0; i < props.numTimes; i++) {
    // 3. 經過調用child elem對應的函數生成jsx obj
    items.push(props.children(i));
  }
  return <div>{items}</div>;
}

// 1. 返回的JSX obj的child elem是個函數
function ListOfTenThings() {
  return (
    <Repeat numTimes={10}>
      {(index) => <div key={index}>This is item {index} in the list</div>}
    </Repeat>
  );
}

Booleans, Null, and Undefined Are Ignored

false, null, undefined, and true are valid children. They simply don’t render. These JSX expressions will all render to the same thing:

<div />

<div></div>

<div>{false}</div>

<div>{null}</div>

<div>{undefined}</div>

<div>{true}</div>

Thinking in React

就是React項目流程的rethinking

Step 1: Break The UI Into A Component Hierarchy

  1. draw boxes around every component (and subcomponent) in the mock and give them all names
  • 使用一些規則(好比單一原則)判斷元素應該屬於哪些部分

[圖片上傳失敗...(image-af5c7e-1512723756201)]

  1. 獲得Component層次列表
  2. 決定數據模型

Step 2: Build A Static Version in React

  1. 先寫個靜態的
  • 重用的Component要準備好
  • 靜態的部分應該不須要用到任何State, State應該僅僅用於動態的Component
  • 從上往下或者從下往上創建均可以, 小型項目從上往下會快一些, 大型項目反之
  1. 改成動態模型
  • 通常最大的那個Component會接受數據做爲所有數據源

Step 3: Identify The Minimal (but complete) Representation Of UI State

  1. 創建項目的時候, 最好能先肯定minimal set of mutable state, 也就是最小動態模塊
  2. 判斷一下動態模塊是否能夠設置成state

以前提到過的三個原則進行判斷:

  1. Is it passed in from a parent via props? If so, it probably isn’t state.
  2. Does it remain unchanged over time? If so, it probably isn’t state.
  3. Can you compute it based on any other state or props in your component? If so, it isn’t state.

Step 4: Identify Where Your State Should Live

  1. 決定哪些Component應該擁有這些State, 哪些Component應該讓State進行變化

React從頭至尾就只有一條數據流有這些須要注意的:

  1. 能夠經過自身State進行render的Component
  2. 最大的那個Component應該擁有State, 用於流程管理之類的業務, 這個State可能包含全部動態成分的內容
  3. 若是沒法找到一個值得擁有一個State的Component, 那就寫個新的, 可能能夠放在最大的State的更上一層

Step 5: Add Inverse Data Flow

就是數據的各類交互唄

一個重要的概念:

有些時候parent class可能會給child class提供一個eventHandler()

這玩意能夠當作一種callback, 賦值給child class的onchange, child class經過調用這個onChange使得parent class的state變化.

若是隻有一個值的狀況下甚至能夠不用給child class設置任何的state# React: 關於setState()

React&Error: setState()不馬上響應到DOM, 老是慢一步

這個八成是由於在setState的同一個方法裏面調用了this.state

這時候獲取到的state都是前一個state

下方是參考文獻:


原文: https://medium.com/@mweststra...
做者: Michel Weststrate

前言

這篇文章原標題是3 Reasons why I stopped using React.setState,可是我對原文做者提出的論點不是很感冒,可是做者提出的三點對React新手來講是很容易忽略的地方,因此我在這裏只提出部份內容,並且把標題改成使用React.setState須要注意的三點。

正文

對React新手來講,使用setState是一件很複雜的事情。即便是熟練的React開發,也頗有可能由於React的一些機制而產生一些bug,好比下面這個例子:

文檔中也說明了當使用setState的時候,須要注意什麼問題:

注意:
絕對不要 直接改變this.state,由於以後調用setState()可能會替換掉你作的改變。把this.state當作是不可變的。

setState()不會馬上改變this.state,而是建立一個即將處理的state轉變。在調用該方法以後訪問this.state可能會返回現有的值。

對setState的調用沒有任何同步性的保證,而且調用可能會爲了性能收益批量執行。

setState()將老是觸發一次重繪,除非在shouldComponentUpdate()中實現了條件渲染邏輯。若是可變對象被使用了,但又不能在shouldComponentUpdate()中實現這種邏輯,僅在新state和以前的state存在差別的時候調用setState()能夠避免沒必要要的從新渲染。

總結出來,當使用setState的時候,有三個問題須要注意:

1. setState是異步的(譯者注:不保證同步的)

不少開發剛開始沒有注意到setState是異步的。若是你修改一些state,而後直接查看它,你會看到以前的state。這是setState中最容易出錯的地方。 setState這個詞看起來並不像是異步的,因此若是你不假思索的用它,可能會形成bugs。下面這個例子很好的展現了這個問題:

class Select extends React.Component {
  constructor(props, context) {
    super(props, context)
    this.state = {
      selection: props.values[0]
    };
  }

  render() {
    return (
      <ul onKeyDown={this.onKeyDown} tabIndex={0}>
        {this.props.values.map(value =>
          <li
            className={value === this.state.selection ? 'selected' : ''}
            key={value}
            onClick={() => this.onSelect(value)}
          >
            {value}
          </li> 
        )}  
      </ul>
    )
  }

  onSelect(value) {
    this.setState({
      selection: value
    })
    this.fireOnSelect()
  }

  onKeyDown = (e) => {
    const {values} = this.props
    const idx = values.indexOf(this.state.selection)
    if (e.keyCode === 38 && idx > 0) { /* up */
      this.setState({
        selection: values[idx - 1]
      })
    } else if (e.keyCode === 40 && idx < values.length -1) { /* down */
      this.setState({
        selection: values[idx + 1]
      })  
    }
    this.fireOnSelect()
  }

  fireOnSelect() {
    if (typeof this.props.onSelect === "function")
      this.props.onSelect(this.state.selection) /* not what you expected..*/
  }
}

ReactDOM.render(
  <Select 
    values={["State.", "Should.", "Be.", "Synchronous."]} 
    onSelect={value => console.log(value)}
  />,
  document.getElementById("app")
)

第一眼看上去,這個代碼彷佛沒有什麼問題。兩個事件處理中調用onSelect方法。可是,這個Select組件中有一個bug很好的展示了以前的GIF圖。onSelect方法永遠傳遞的是以前的state.selection值,由於當fireOnSelect調用的時候,setState尚未完成它的工做。我認爲React至少要把setState更名爲scheduleState或者把回掉函數設爲必須參數。

這個bug很容易修改,最難的地方在於你要知道有這個問題。

2. setState會形成沒必要要的渲染

setState形成的第二個問題是:每次調用都會形成從新渲染。不少時候,這些從新渲染是沒必要要的。你能夠用React performance tools中的printWasted來查看何時會發生沒必要要渲染。可是,大概的說,沒必要要的渲染有如下幾個緣由:

  • 新的state其實和以前的是同樣的。這個問題一般能夠經過shouldComponentUpdate來解決。也能夠用pure render或者其餘的庫來解決這個問題。

  • 一般發生改變的state是和渲染有關的,可是也有例外。好比,有些數據是根據某些狀態來顯示的。

  • 第三,有些state和渲染一點關係都沒有。有一些state多是和事件、timer ID有關的。

3.setState並不能頗有效的管理全部的組件狀態

基於上面的最後一條,並非全部的組件狀態都應該用setState來進行保存和更新的。複雜的組件可能會有各類各樣的狀態須要管理。用setState來管理這些狀態不但會形成不少不須要的從新渲染,也會形成相關的生命週期鉤子一直被調用,從而形成不少奇怪的問題。

後話

在原文中做者推薦了一個叫作MobX的庫來管理部分狀態,我不是很感冒,因此我就不介紹。若是感興趣的,能夠經過最上面的連接看看原文中的介紹。

基於上面提出的三點,我認爲新手應該注意的地方是:

setState是不保證同步的

setState是不保證同步的,是不保證同步的,是不保證同步的。重要的事情說三遍。之因此不說它是異步的,是由於setState在某些狀況下也是同步更新的。能夠參考這篇文章

若是須要在setState後直接獲取修改後的值,那麼有幾個方案:

傳入對應的參數,不經過this.state獲取

針對於以前的例子,徹底能夠在調用fireOnSelect的時候,傳入須要的值。而不是在方法中在經過this.state來獲取

使用回調函數

setState方法接收一個function做爲回調函數。這個回掉函數會在setState完成之後直接調用,這樣就能夠獲取最新的state。對於以前的例子,就能夠這樣:

this.setState({
  selection: value
}, this.fireOnSelect)

使用setTimeout

在setState使用setTimeout來讓setState先完成之後再執行裏面內容。這樣子:

this.setState({
  selection: value
});

setTimeout(this.fireOnSelect, 0);

直接輸出,回調函數,setTimeout對比

    componentDidMount(){
    this.setState({val: this.state.val + 1}, ()=>{
      console.log("In callback " + this.state.val);
    });

    console.log("Direct call " + this.state.val);   

    setTimeout(()=>{
      console.log("begin of setTimeout" + this.state.val);

       this.setState({val: this.state.val + 1}, ()=>{
          console.log("setTimeout setState callback " + this.state.val);
       });

      setTimeout(()=>{
        console.log("setTimeout of settimeout " + this.state.val);
      }, 0);

      console.log("end of setTimeout " + this.state.val);
    }, 0);
  }

若是val默認爲0, 輸入的結果是:

> Direct call 0
> In callback 1
> begin of setTimeout 1
> setTimeout setState callback 2
> end of setTimeout 2
> setTimeout of settimeout 2

和渲染無關的狀態儘可能不要放在state中來管理

一般state中只來管理和渲染有關的狀態,從而保證setState改變的狀態都是和渲染有關的狀態。這樣子就能夠避免沒必要要的重複渲染。其餘和渲染無關的狀態,能夠直接以屬性的形式保存在組件中,在須要的時候調用和改變,不會形成渲染。或者參考原文中的MobX。

避免沒必要要的修改,當state的值沒有發生改變的時候,儘可能不要使用setState。雖然shouldComponentUpdate和PureComponent能夠避免沒必要要的重複渲染,可是仍是增長了一層shallowEqual的調用,形成多餘的浪費。

以上

React: Form裏面判斷checkbox.md

handleStockedChange(e){
    var value = e.target.type === 'checkbox' ? e.target.checked : e.target.value;
  }

React: 關因而否應該將某個變量做爲state.md

  1. Is it passed in from a parent via props? If so, it probably isn’t state.
  2. Does it remain unchanged over time? If so, it probably isn’t state.
  3. Can you compute it based on any other state or props in your component? If so, it isn’t state.# React&Error: Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null

八成就是return後面換行了, JS會自動加分號因此返回了undefined

React&Error: Unterminated JSX contents

這個八成就是寫了兩個elem或者某個elem沒有閉合

Composition vs Inheritance

不推薦使用繼承

我也不推薦

示例

Anything inside the <FancyBorder> JSX tag gets passed into the FancyBorder component as a children prop.

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


function WelcomeDialog() {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        Welcome
      </h1>
      <p className="Dialog-message">
        Thank you for visiting our spacecraft!
      </p>
    </FancyBorder>
  );
}

React: Form/Inputs

通常h5的input本身會管理本身的輸入

Controlled Components

<span style="color: red;"> 實際上就是兩點:</span>

  1. 給value綁定一個state的值, state.value最好
  2. 給onChange綁定一個事件, 修改state.value

React也能夠在渲染的時候綁定事件, 事件裏面就能夠進行各類操做, 好比轉換全部文本爲uppercase之類的。另外修改了文本以後也能夠馬上反應/渲染到元素之上。

相似於將JS端的onChange放到了Server

  handleChange(event) {
    //經過變量event.target.value獲取輸入的值而且設置state
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('A name was submitted: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>  //綁定onSubmit
        <label>
          Name:
          <input type="text" value={this.state.value} onChange={this.handleChange} /> //綁定onChange
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }

The textarea Tag

有一點和H5不一樣的地方, React端的value的設置能夠經過一個attr:

H5:

<textarea>
  Hello there, this is some text in a text area
</textarea>

React:

<textarea value={this.state.value} onChange={this.handleChange} />

The select Tag

設置selected的option的時候也略有不一樣, 一樣能夠經過value這個attr設置

H5:

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

React:

 <select value={this.state.value} onChange={this.handleChange}>
            <option value="grapefruit">Grapefruit</option>
            <option value="lime">Lime</option>
            <option value="coconut">Coconut</option>
            <option value="mango">Mango</option>
          </select>

關於使用Value=Null來容許用戶輸入

能夠看到, 將input的value設置爲this.state.value就是爲了阻止用戶自由輸入, 可是有些時候要將controlled Input的權限放開, 所以咱們能夠將value設置爲null或者undefined來開啓用戶自由輸入.

ReactDOM.render(<input value="hi" />, mountNode);

// allow user input after 1sec
setTimeout(function() {
  ReactDOM.render(<input value={null} />, mountNode);
}, 1000);

關於Controlled Components 和 UnControlled Components

縮寫成CC/UC

CC寫起來其實挺麻煩, 由於每一個elem都要寫個onChange.
其實也可使用UC

使用UC的例子:

  1. 使用一個ref將輸入的值賦給多個參數, 好比this.xxx
  2. submit的時候對this.xxx進行各類validation以及處理
  handleSubmit(event) {
    alert('A name was submitted: ' + this.input.value);
    event.preventDefault();
  }

 render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input type="text" ref={(input) => this.input = input} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }

React: 關於使用Keys來索引列表.md

通常將key放置到列表class裏面進行賦值, 而不是放到item裏面進行賦值

最好放在ul循環生成li的時候給li添加key

function ListItem(props) {
  const value = props.value;
  return (
  
    // Wrong! There is no need to specify the key here
    // 固然在這兒也得到不到key值
    <li key={value.toString()}>
      {value}
    </li>
    
  );
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
  
    // Wrong! The key should have been specified here:
    <ListItem value={number} />
    
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

正確用法:

function ListItem(props) {
  // Correct! There is no need to specify the key here:
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // Correct! Key should be specified inside the array.
    <ListItem key={number.toString()}
              value={number} />
  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

React: 關於render()裏面隱藏一個元素.md

不要return一個JSX Obj, return null 便可

React: 關於使用Inline Expressions.md

If-then

return (
    <div>
      <h1>Hello!</h1>
      {unreadMessages.length > 0 &&  //注意這裏, 前面實際上是一個條件
        <h2>
          You have {unreadMessages.length} unread messages.
        </h2>
      }
    </div>
  );

If-Else

  return (
    <div>
      The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
    </div>
  );
 return (
    <div>
      {isLoggedIn ? (
        <LogoutButton onClick={this.handleLogoutClick} />
      ) : (
        <LoginButton onClick={this.handleLoginClick} />
      )}
    </div>
  );

React: Handling Events

幾個要點:

  • React events are named using camelCase, rather than lowercase.
  • With JSX you pass a function as the event handler, rather than a string.

For example, the HTML:

<button onclick="activateLasers()">
  Activate Lasers
</button>

is slightly different in React:

<button onClick={activateLasers}>
  Activate Lasers
</button>

Another difference is that you cannot return false to prevent default behavior in React. You must call preventDefault explicitly.

防止默認事件的代碼須要一些修正

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

In React, this could instead be:

function ActionLink() {
  function handleClick(e) {
    e.preventDefault(); // must be called implicitly 
    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}

When using React you should generally not need to call addEventListener to add listeners to a DOM element after it is created.

Instead, just provide a listener when the element is initially rendered.

初始化的時候給事件管理器,DOM初始化以後就別去添加其餘監聽器了。

JQuery: ...

示例

class Welcome extends React.Component{
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};
    this.handleClick = this.handleClick.bind(this);  //綁定一下事件到this
  }

  handleClick() {
    console.log(123)
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }

  render(){
    return (
      <div onClick={this.handleClick}>  //這裏記得要寫一個attr,而且要注意大小寫
       {(this.state.isToggleOn)?'A':'B'}, {this.props.name}
      </div>
    );
  }
}

Passing Arguments to Event Handlers

下方的ID表明對應數據編號, 既可使用外部的循環Index.

這兒有點像是閉包

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

兩種模式相似, 重點在於必定要將React event傳進去

  1. 對於Arrow Function來講, 須要顯示傳入
  2. 對於bind()來講就不用了

來源: https://reactjs.org/docs/handling-events.html

React&Error: Cannot call a class as a function.md

class component看起來不能經過函數的方式進行調用
那麼就改爲tag模式調用就行:

  render(){
    return (
      <div>
      <WelcomeLList nameList={nameList}/>
      // {WelcomeList(this.props.nameList)} 
      // ↑↑ dont use this way if you created class component 
      </div>
    );
  }

React&Tips: 關於在Render裏面使用變量.md

其實和Java的class同樣,render裏面能夠直接調用prop參數了

class Root extends React.Component{
  constructor(props) {
    super(props);
  }

  render(){
    return (
      <div>
      {WelcomeList(this.props.nameList)}    //這裏能夠直接使用this.prop
      </div>
    );
  }
}

在React中使用數組做爲參數

簡單易懂,直接賦值一個數組便可,不用加雙引號,否則會被當作長字符串

var nameList = ["Mike","Jack","Dick"];
ReactDOM.render(
  <Root nameList={nameList}/>,
  // <Root nameList="{nameList}"/>, // This is wrong
  document.getElementById('root')
);

React: 關於States.md

相似於Android的生命週期調節參數,此外state必須在定義它的那個class裏面使用。

另外能夠將state傳到子元素,不過不能傳給其餘同級元素或者父元素

所以只可能出現Down Flow不可能向上傳遞。

另外stateful的Component和stateless的Component徹底能夠隨意交叉使用,反正數據均可以相互傳遞

<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
<FormattedDate date={this.state.date} />

生命週期

對於一個Component:

  • 初始化的時候的操做叫作Mounting
  • 銷燬的操做叫作unMounting

而後能夠在這兩個事件進行監聽

  • componentDidMount()事件會在Component渲染成功時執行
  • componentWillUnmount()事件會在Component銷燬的時候執行

所以對於一個定時器來講,應該在componentDidMount()事件裏面註冊Timer而且在componentWillUnmount()事件裏面關閉Timer

而後在Timer裏面必須更新state數據,由於咱們會將state數據輸出出來,更新state須要執行setState(),將參數傳進去就行

簡單易懂

Timer的示例

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date()
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

Using State Correctly

幾個關於setState()的要點:

1. Do Not Modify State Directly

// Wrong
this.state.comment = 'Hello';

// Correct
this.setState({comment: 'Hello'});

The only place where you can assign this.state is the constructor.

2. State Updates May Be Asynchronous

所以不能直接使用state來overwite state

React may batch multiple setState() calls into a single update for performance.

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

For example, this code may fail to update the counter:

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

To fix it, use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:

寫一個閉包能夠解決問題

// Correct
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

3. State Updates are Merged

When you call setState(), React merges the object you provide into the current state.

使用 setState()的時候,只要沒有提供value的state都不會改變

For example, your state may contain several independent variables:

  constructor(props) {
    super(props);
    this.state = {
      posts: [],
      comments: []
    };
  }

Then you can update them independently with separate setState()calls:

  componentDidMount() {
    fetchPosts().then(response => {
      this.setState({
        posts: response.posts
      });
    });

    fetchComments().then(response => {
      this.setState({
        comments: response.comments
      });
    });
  }

The merging is shallow, so this.setState({comments}) leaves this.state.posts intact, but completely replaces this.state.comments.

Converting a Function to a Class

  • You can convert a functional component like Clock to a class in five steps:
  • Create an ES6 class with the same name that extends React.Component.
  • Add a single empty method to it called render().
  • Move the body of the function into the render() method.
  • Replace props with this.props in the render() body.
  • Delete the remaining empty function declaration.
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

Adding Local State to a Class

We will move the date from props to state in three steps:

  1. Replace this.props.date with this.state.date in the render() method:
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

  1. Add a class constructor that assigns the initial this.state:
class Clock extends React.Component {
  constructor(props) {  //!!!!!!!!!!!!!!
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

Note how we pass props to the base constructor:

  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

Class components should always call the base constructor with props.

  1. Remove the date prop from the <Clock /> element:
ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

We will later add the timer code back to the component itself.

The result looks like this:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

來源: https://reactjs.org/docs/state-and-lifecycle.html

React: 關於Local States.md

React: JSX裏面循環生成多個子元素.md

用這個方法能夠循環生成多個子元素

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

function WelcomeList(nameList) {
    var nameDOM = [];
    for (var i = 0; i < nameList.length; i++) {
        nameDOM.push(Welcome({name: nameList[i]}))
    }
    return nameDOM;
}

function Root() {
    var nameList = ["Mike","Jack","Dick"];
  return (
    <div>
        {WelcomeList(nameList)}
    </div>
  );
}

ReactDOM.render(
  <Root />,
  document.getElementById('root')
);
相關文章
相關標籤/搜索