JavaScript 和 React,React用了大量語法糖,讓JS編寫更方便。



https://reactjs.org/docs/higher-order-components.html https://codepen.io/gaearon/pen/WooRWa?editors=0010

JSX in Depth

 

https://babeljs.io/  JS編譯器,學習react和JS直接的轉換。

 JSX僅支持句法糖syntactic sugar:

 

React.createElement(component, props, ...children)函數,

JSX code:

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

 編譯compiles into:

React.createElement(

  MyButton,
  {color: 'blue', shadowSize: 2},
  'Click Me'
)   

 

也可以使用self_closing form of the tag if there are no children. So:

<div className="sidebar" />

compiles into:

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

 

函數形式的:

function hello() {

  return <div>Hello world!</div>; 

轉換為:

function hello() {
  return React.createElement(
    'div',
    null,
    'Hello world!'
  );
}

關於React元素的格式: 

 

React 一定在Scope內。

 

使用. Dot Notaiton ,可以在JSX中使用點符號。如果一個模塊要調出一些React組件,這樣就方便了。例子:

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" />;
}

 

自定義的組件必須首字母大寫(除非分配它一個首字母大寫的變量)。function Hello(props){...} 

 

在運行時選擇類型Choosing the type at runtime 

不能把表達式用做React element type。但是可以把它分配給一個大寫字母的變量,然后就可以間接用JSX格式了

 

import React from 'react';
import { PhotoStory, VideoStory } from './stories';
const components = {
  photo: PhotoStory,
  video: VideoStory
};
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} />;
}

 


 Props in JSX

 

通過{}, 任何JS expression 都可以作為props. 例如<MyComponent foo={1 + 2 + 3 + 4} />

 

if statements and for loops 不是JS表達式,不能直接用於JSX。但{}就能用了

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

 

條件判斷 Inline的寫法: 

{true && expression}  //如果是true,則執行表達式。 

{condition ? true : false }

 

防止組件被渲染:

return null; ⚠️,組件的lifecycle 方法鈎子方法,仍然生效componentWillUpdate 和 componentDidUpdate。

 


 

 

Children in JSX

 

string Literals

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

&amp; 就是& 

編譯:

React.createElement(
  "div",
  null,
  "This is valid HTML & JSX at the same time."
);

JSX移除一行開頭和結尾的空格

 

JSX Children

支持內嵌JSX元素作為孩子。在嵌套組件中很有用。

React組件也返回數組元素。return [, ,]; 

 

JS expression也可以作為孩子。

function Item(props) {
  return <li>hello,  {props.message} </li>;  //props.children
}
function TodoList() {
  const todos = ['finish', 'submit ', 'review'];
  return (
    <ul>

//這個是函數作為props.children。 

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

 

Function as Children 

 見標黃的代碼.React.createElement(component, props,...child)

 

function Repeat(props) {

 

  let items = [];
  for (let i= 0; i < props.numTimes; i++) {
    items.push( props.children(i) );
  }
  return <div>{items}</div>;
}
function ListOfTenThings() {
  return (
    <Repeat numTimes={10}>
      {(index) => <div key={index}>{index}:This is item {index}</div>}
    </Repeat>
  );
}

 

Booleans, Null, and Undefined are Ignored. 

false ,null, undefined, true都是驗證的孩子,不過它們不渲染。

所以可以作為條件判斷 condition && expression。

如果showHeader是true則渲染<Header />

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

⚠️ 0會被渲染

如果要讓true渲染使用類型轉換,String()。 

 

 

 


 

Typechecking With PropTypes(未看)

用於檢查輸入的一個方法PropTypes ,這是React內置的方法,JS擴展中也有Flow,TypeScript等擴展插件。

大型的代碼檢查,官方推薦使用Flow or TypeScript 而不是用默認的。 

https://reactjs.org/docs/typechecking-with-proptypes.html 

PropTypes輸出了一組驗證器用於確保你接收的數據是通過驗證的。如果一個未通過驗證的值提供給一個prop,一條warning會顯示在JS console中。propTypes只用於開發模式。

import PropTypes from 'prop-types';
class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}
Greeting.propTypes = {
  name: PropTypes.string    //確保是string類的值,否則報告⚠️信息。
};

 


Refs ans the DOM(未看)

https://reactjs.org/docs/refs-and-the-dom.html 

 

在典型的數據流模式,組件之間的交互使用props。但有少數情況屬於例外情況。

Refs提供了一個方法,能夠使用DOM nodes 和React elements created in the render method。React提供了這個escape hatch逃生艙門。

何時用:

 

  • 管理focus,text selection ,media playback
  • 合並第三方DOM庫
  • 打開必要的動畫Triggering imperative animations 
React.createRef:

創建一個ref可以附加到React elements 

this.myRef = React.createRef() 並通過ref屬性付給React元素

 


 

Uncontrolled Components 

 

推薦使用controlled components 來實現forms, 這時,表格數據被React組件處理。

但我們也可以用別的方式,這時,表格data被DOM自身處理。 

既然非控制組件保持了DOM的原生性,有時它比較容易合並React和非React代碼。如果你想要更快並不在乎代碼太臟(可讀性差),也能夠稍微少輸入點代碼。

你應該盡量用可控制的組件。

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

 紅字是用原生DOM加ref。

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.handleTextChange = this.handleTextChange.bind(this);
    this.state = {text: ""};
  }
  
  handleTextChange(e) {
    this.setState({text: e.target.value});
  }
  
  handleSubmit(e) {
    // alert("A name was submitted: " + this.input.value);
    alert("A name was submitted: " +  this.state.text);
    e.preventDefault();
  }
  
  render() {
    return (
      // <form onSubmit={this.handleSubmit}>
      //   <label>
      //     Name:
      //     <input type="text" ref={(input) => this.input = input}  />
      //   </label>
      //   <input type="submit" value="Submit" />
      // </form>
      <form>
        <label>
          Name:
          <input type="text" onChange={this.handleTextChange}/>
        </label>
        <input type="submit" value="Submit" onClick={this.handleSubmit} />
      </form>
    );
  }
}
ReactDOM.render(
  <NameForm />,
  document.getElementById('example')
);

 

 


 

 

Optimizing Performance(略讀)

優化執行的方法和工具。

使用React Developer Tools for Chrome.(也有其他瀏覽器版本) 

這個工具可以制作Timeline可視化每個組件mount update, unmount. 

 


 

Context(一個不使用傳統方法傳遞數據的方法。)

https://reactjs.org/docs/context.html 

一整章節,暫時不看。


 Fragments

讓你返回多個元素在一個render()方法中,不需要創建一個額外的DOM 元素。

The  React.Fragment  component lets you return multiple elements in a  render() method without creating an additional DOM element:

 

render() {
  return (
    <React.Fragment>
      <ChildA />
      <ChildB />
      <ChildC />
    </React.Fragment>
  );
}

這時如果是靜態的可以不加key,最好加上。另外用[]也可以,但必須加key

 

 HTML description list:

<dl>

  <dt>

    <dd></dd>

  </dt> 

</dl> 

 


 

Portals

大門,入口。 

https://reactjs.org/docs/portals.html 

渲染孩子進入一個Dom節點 

ReactDOM.createPortal(child,container) 

第一個參數是任意的渲染的React child。如an element, string, or fragment. 

第二個參數container是一個DOM元素。 

一般來說,從一個組件的渲染方法中返回一個元素,它作為孩子附加在離它最近的父節點后。

而使用createPortal這樣就可以插入一個孩子到DOM中不同的位置。 (但仍然受到父組件event事件的影響)

 案例:https://codepen.io/gaearon/pen/yzMaBd?editors

    return (
      <div className="app">
        This div has overflow: hidden.
        <button onClick={this.handleShow}>Show modal</button>
        {modal}  //看似是在這個block中,其實Modal組件使用了createProtal()把自己插入到了其他DOM節點。
      </div>
    );

 

Event Bubbling Through Portals

a portal可以插入到在DOM tree的任何位置,不過它在其他方面仍舊是一個普通的React child。

假如:在一個父組件中渲染一個子組件(Modal),那么Modal就可以被這個父組件捕捉到。這個父組件不會考慮Modal是否用了protals。

即便Modal用了protal把代碼插入到不屬於父組件的其他節點,父組件仍然可以捕捉到Modal,父組件定義了一個點擊事件,對Modal中的元素進行點擊也會觸發父組件的點擊事件。

案例:https://codepen.io/chentianwei411/pen/ZoLeBE?editors=0010 

 


 

 

Error Boundaries 

錯誤邊界。 目的:解決僅僅是部分UI的錯誤就會造成整個app崩潰的問題。

Error boundaries也是一個React組件。JS 錯誤發生在子組件的任何位置,它都可以捕捉到,並且log those errors, 並且display a fallback UI。

Error boundaries 捕捉錯誤是在渲染的時候,因此lifecycle methods 和 constructors of the whole tree都低於Error boundaries.

⚠️以下超出了Error-b的使用范圍:

Event handlers, 異步代碼, 服務器端渲染, 自身拋出錯誤。

 

 


 

 

Higher-Order Components (基本用法,一些約定沒有看。)

 

一種代碼的抽象化, 根據dry原則,把有相同邏輯的組件重構。

即重構一個函數,這個函數接受一個組件並return 一個新組件。 

 

要點:發現有很多相同邏輯(內部代碼基本一樣)的組件, 為了減少代碼的量和便於閱讀維護。

 https://reactjs.org/docs/higher-order-components.html

 

 // 調用Highter-Order組件withSubscription.把返回的新組件存入一個JSX.

const CommentListWithSubscription = withSubscription(

  CommentList,

  (DataSource) => DataSource.getComments() 

); 

 

const BlogPostWithSubscription = withSubscription(
  BlogPost,
  (DataSource, props) => DataSource.getBlogPost(props.id)
);

 

function withSubscription(WrappedComponent,  selectData) {

  //WrappedComponent是組件名字, selectData是數據及其使用的methods。 

  return class extends React.Component {...} ;  //class后面沒有組件名字

 

⚠️ ,不要在higher-order組件中對原有組件修改,如果需要組件進行功能的變化,把這個變化寫在return中。

⚠️, 約定convension: 傳遞不相關的props,通過wrapped 組件。 在render方法中使用不相關的props.

 

 

 


 

Render Props

 

術語render prop是一個簡單的技術:在React組件之間,通過使用一個值是函數的prop來分享代碼。

The term "render prop" refers to a simple technique for sharing code between React components using a prop whose value is a function. 

<DataProvider render={data => (
  <h1>Hello {data.target}</h1>
)}/>

一個組件帶着一個render prop,這個組件渲染的時候可以使用這個render prop的值

a render prop is a function prop that a component uses to know what to render.

 https://reactjs.org/docs/render-props.html

 


 


React.Component 

 

組件的lifecycle methods

Methods prefixed with will are called right before sth happens. did are called after sth happens. 

 

Mounting

這些方法在一個組件實例被創建和插入DOM時調用。 

 

constructor(props){...}   //在加載組件前調用。

before it is mounted,如果組件是一個子類,還需要在其他聲明前面調用super(props)。 constructor()用於初始化state。也用於bind event-handlers to the class instance.

分配給this.state的對象可以包含props。但⚠️這不是時時更新的,最好不這么用,例子: 

  this.state = {
    color: props.initialColor
  };


UNSAFE_componentWillMount()   //在加載組件前引用。它在render()前調用。

 

render() 

When called, it should examine this.props and this.state and return one of the following types:

 

  • React elements. 包括自定義的組件或原生的DOM component <div />
  • String and numbers. 作為text nodes 渲染在DOM中。
  • Portals. Created with ReactDOM.createPortal 
  • null 什么也不加載
  • Booleans。一般用於 return test && <Child />模式,當test是true時,加載后面
⚠️ shouldComponentUpdate()方法返回false時,不加載render()

 

 

componentDidMount()   //在組件加載后立即引用

用途:

加載遠程endpoint的數據,這里可以實例化network request。

也可以建立任何訂閱並配合componentWillUnmount()取消訂閱。 

調用setState(),會激活額外的rendering. 

 

Updating

 一個update會被props或state的改變引起。下面的方法當一個組件被再加載時調用。(只看了其中幾個,一共7個方法)

 

componentWillReceiveProps() 

在一個已經加載的組件再次接收新的props之前引用這個方法。 這個方法限制很多不推薦用。

 

shouldComponentUpdate(nextProps, nextState)

返回true,false。讓React知道一個組件的輸出是否被當前state or propsde 變化所影響。如果是true,則組件再render()。方法默認是true。所以一般不主動使用這個方法。 

如果是false,render(), componentWillUpdate(), componentDidUpdate()不會調用。

 

componentWillUpdate(nextProps, nextSate)

當一個新props or state 被接收到后,在渲染之前引用。

 

render() 

每次更新props or state后,調用render(). 

 

componentDidUpdate(prevProps, prevState, snapshot) 

在更新發生后,立即引用。

 

Unmounting

  • componentWillUnmount(): 在一個組件被卸載和刪除前立即引用。用於執行必要的清潔。如未驗證的timers, 取消網絡請求, 清潔任何在componentDidMount()中的訂閱
Error Handing
  •  componentDidCatch():這個方法被調用當一個❌發生在渲染中,在lifecyle方法中,或者在一個孩子組件的constructor中。

Other APIS

 

setState()

enqueuqs changes to the component state and tells React that this component and its children need to be re-rendered with the updated state.

改變組件的狀態state並告訴React“組件和它的孩子需要根據更新的state再渲染”

這是一個主要的方法,用來更新user interface in response,事件處理和服務器響應。

 

把setState()當作一個request,而不是更新組件的即時命令。 

setState()不總是立即執行更新組件,因為它類似request,有延遲。因此,使用componentDidUpdate或者setState(updater, callback)可以保證fire(立即執行).


setState(updater, callback)

updater是一個函數:(prevState, props) => stateChange   //prevState是之前state的一個引用。 例子:用props.step增加一個值到state中。

this.setState((prevState, props) => {
  return {counter: prevState.counter + props.step};
}); 

callback參數是可選的函數。在setState完成更新,組件被再渲染后執行這個函數,推薦使用componentDidUpdate代替。 

 

第一個參數可以是一個對象object.代替一個函數。 這個執行會把狀態變化合並到新狀態中。 

this.setState({quantity: 2}) 

 

forceUpdate() 

component.forceUpdate(callback),如果render()方法依靠其他數據源,你可以告訴組件調用forceUpdate()來再渲染。個人理解:這個方法就是用來執行渲染的。

 

 

Class Properties

 

defaultProps

給組件的property設定默認值。 

class CustomButton extends React.Component {
  // ...
}
CustomButton.defaultProps = {
  color: 'blue'
};

渲染的時候自動增加上color="blue"

render() {
  return <CustomButton /> ; // props.color will be set to blue
}

 

 displayName 

 https://reactjs.org/docs/higher-order-components.html#convention-wrap-the-display-name-for-easy-debugging

debug用。

 

Instance Properties

  • props
  • state 

 


 

 


 

 

ReactDOM 

import ReactDOM from 'react-dom'

react-dom package提供了DOM-specific methods。大多數組件不需要使用這個module.

 

ReactDOM.render(element, container[, callback]) 

渲染一個React element到DOM中。具體位置是container, 返回a reference 給組件。

如果之前已經渲染進container中,更新時只修改必要的部分。

callback可選,在組件渲染或更新后執行.\

 

createPoratal() 

ReactDOM.createPortal(child, container) 


hydrate()
unmountComponentAtNode()
findDOMNode()

 


ReactDOMServe

import ReactDOMServer from 'react-dom/server'; 

用於把組件渲染到靜態標記中,一般用於一個Node server

 

這兩個方法可以用於server,也可以用在瀏覽器。 

renderToString()

renderToStaticMarkup() 

 

ReactDOMServer.renderToString(element) 

渲染一個React元素到 原始HTml. React返回一個HTML string。

 


 

DOM Elements

https://reactjs.org/docs/dom-elements.html 

 

style 

style屬性可以接受JS 對象。屬性要用駝峰寫法。如backgroundImage. px可以省略

const divStyle = {
  color: 'blue',
  background: 'lightblue',
};
function Hello() {
  return < div style={divStyle} >Hello World!</div>;
}

 

value 

<input>, <textarea>組件支持value屬性。

 

className 

用來指定css class的名字。

 

checked 

<input>組件中的type類型為checkbox or radio的支持這個屬性。 

All Supported HTML Attributes 

 

 


 

SyntheticEvent 

人工事件

event handlers被傳到人工事件的實例,一個跨瀏覽器的包裹器(包含瀏覽器的原生事件)。

每個SyntheticEvent對象有一系列的屬性attributes:如:

currentTarget, target, type, timeStamp, isTrusted, preventDefault()等等。 

 

 https://reactjs.org/docs/events.html

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM