React基礎學習總結

一、JSX語法

1、花括號 { } 把任意的 [JavaScript 表達式]嵌入到 JSX 中

function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}

const user = {
  firstName: 'Harper',
  lastName: 'Perez'
};

const element = (
  <h1>
    Hello, {formatName(user)}!
  </h1>
);

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

2、JSX可作表達式

可以在 if 語句或者是 for 循環(huán)中使用 JSX,用它給變量賦值,當做參數(shù)接收,或者作為函數(shù)的返回值

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

3、用 JSX 指定屬性值

(1)用雙引號 “” 來指定字符串字面量作為屬性值
(2)用花括號 {} 嵌入一個 JavaScript 表達式作為屬性值
在屬性中嵌入 JavaScript 表達式時,不要使用引號來包裹大括號。否則,JSX 將該屬性視為字符串字面量而不是表達式。對于字符串值你應該使用引號,對于表達式你應該使用大括號,但兩者不能同時用于同一屬性。

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

const element = <img src={user.avatarUrl}></img>;
4、用 JSX 指定子元素

(1)如果是空標簽,您應該像 XML 一樣,使用 />立即閉合它
(2)JSX 標簽可能包含子元素

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

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

5、JSX 表示對象

Babel 將JSX編譯成 React.createElement() 調(diào)用。

//兩種形式等價
const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);

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

二、元素渲染

元素(Elements)是 React 應用中最小的構建部件(或者說構建塊,building blocks),不同于組件。

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

1、渲染一個元素到 DOM

要渲染一個 React 元素到一個 root DOM 節(jié)點,把它們傳遞給 ReactDOM.render() 方法:

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

2 、更新已渲染的元素

React 元素是不可突變的. 一旦你創(chuàng)建了一個元素, 就不能再修改其子元素或任何屬性。一個元素就像電影里的一幀: 它表示在某一特定時間點的 UI 。更新 UI 的唯一方法是創(chuàng)建一個新的元素, 并將其傳入 ReactDOM.render()方法.

3、React 只更新必需要更新的部分

React DOM 會將元素及其子元素與之前版本逐一對比, 并只對有必要更新的 DOM 進行更新, 以達到 DOM 所需的狀態(tài)。

三、組件(Components) 和 屬性(Props)

組件使你可以將 UI 劃分為一個一個獨立,可復用的小部件,并可以對每個部件進行單獨的設計。

1、函數(shù)式組件和類組件

//函數(shù)式組件
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

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

2、渲染組件

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

const element = <Welcome name="Sara" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);
  1. 我們調(diào)用了 ReactDOM.render() 方法并向其中傳入了 <Welcome name="Sara" /> 元素。
  2. React 調(diào)用 Welcome 組件,并向其中傳入了 {name: 'Sara'} 作為 props 對象。
  3. Welcome 組件返回 <h1>Hello, Sara</h1>。
  4. React DOM 迅速更新 DOM ,使其顯示為 <h1>Hello, Sara</h1>。

注意:

  • 組件名稱總是以大寫字母開始。
    <div /> 代表一個 DOM 標簽,而 <Welcome /> 則代表一個組件,并且需要在作用域中有一個 Welcome 組件。
  • 組件必須返回一個單獨的根元素。這就是為什么我們添加一個 <div> 來包含所有 <Welcome /> 元素的原因。
function App() {
  return (
    <div>
      <Welcome name="Sara" />
      <Welcome name="Cahal" />
      <Welcome name="Edite" />
    </div>
  );
}

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

3、提取組件

提取組件可能看起來是一個繁瑣的工作,但是在大型的 Apps 中可以回報給我們的是大量的可復用組件。一個好的經(jīng)驗準則是如果你 UI 的一部分需要用多次 (Button,Panel,Avatar),或者本身足夠復雜(App,F(xiàn)eedStory,Comment),最好的做法是使其成為可復用組件。

function Comment(props) {
  return (
    <div className="Comment">
      <UserInfo user={props.author} />
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

4、所有 React 組件都必須是純函數(shù),并禁止修改其自身 props

四、狀態(tài)(State) 和 生命周期

1、把函數(shù)式組件轉化為類組件

遵從以下5步, 把一個類似 Clock這樣的函數(shù)式組件轉化為類組件:

  1. 創(chuàng)建一個繼承自 React.Component類的 ES6 class 同名類。
  2. 添加一個名為 render() 的空方法。
  3. 把原函數(shù)中的所有內(nèi)容移至 render() 中。
  4. 在 render() 方法中使用 this.props 替代 props。
  5. 刪除保留的空函數(shù)聲明。

Clock 現(xiàn)在被定為類組件,而不是函數(shù)式組件。
類允許我們在其中添加本地狀態(tài)(state)和生命周期鉤子。

class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

2、在類組件中添加本地狀態(tài)(state)

我們現(xiàn)在通過以下3步, 把date從屬性(props) 改為 狀態(tài)(state):

class Clock extends React.Component {

2、添加一個 類構造函數(shù)(class constructor)初始化 this
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }


1、替換 render() 方法中的 this.props.date 為 this.state.date
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}


3、移除 <Clock /> 元素中的 date 屬性
ReactDOM.render(
  <Clock />,
  document.getElementById('root')
);

3、在類中添加生命周期方法

在一個具有許多組件的應用程序中,在組件被銷毀時釋放所占用的資源是非常重要的。

當 Clock 第一次渲染到DOM時,我們要設置一個定時器。 這在 React 中稱為 “掛載(mounting)” 。
當 Clock 產(chǎn)生的 DOM 被銷毀時,我們也想 清除該計時器 。 這在 React 中稱為 “卸載(unmounting)” 。

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


1、this.props 由 React 本身設定, 而 this.state 具有特殊的含義,但如果需要存儲一些不用于視覺輸出的內(nèi)容,則可以手動向類中添加額外的字段。
如果在 render() 方法中沒有被引用, 它不應該出現(xiàn)在 state 中。

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

2、我們在componentWillUnmount()生命周期鉤子中取消這個計時器
  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')
);

回顧一下該過程,以及調(diào)用方法的順序:

  1. 當 <Clock /> 被傳入 ReactDOM.render() 時, React 會調(diào)用 Clock組件的構造函數(shù)。 因為 Clock 要顯示的是當前時間,所以它將使用包含當前時間的對象來初始化 this.state 。我們稍后會更新此狀態(tài)。
  2. 然后 React 調(diào)用了 Clock 組件的 render() 方法。 React 從該方法返回內(nèi)容中得到要顯示在屏幕上的內(nèi)容。然后,React 然后更新 DOM 以匹配 Clock 的渲染輸出。
  3. 當 Clock 輸出被插入到 DOM 中時,React 調(diào)用 componentDidMount() 生命周期鉤子。在該方法中,Clock 組件請求瀏覽器設置一個定時器來一次調(diào)用 tick()。
  4. 瀏覽器會每隔一秒調(diào)用一次 tick()方法。在該方法中, Clock 組件通過 setState() 方法并傳遞一個包含當前時間的對象來安排一個 UI 的更新。通過 setState(), React 得知了組件 state(狀態(tài))的變化, 隨即再次調(diào)用 render() 方法,獲取了當前應該顯示的內(nèi)容。 這次,render() 方法中的 this.state.date 的值已經(jīng)發(fā)生了改變, 從而,其輸出的內(nèi)容也隨之改變。React 于是據(jù)此對 DOM 進行更新。
  5. 如果通過其他操作將 Clock 組件從 DOM 中移除了, React 會調(diào)用 componentWillUnmount() 生命周期鉤子, 所以計時器也會被停止。

4、正確地使用 State(狀態(tài))

setState() 有三件事是你應該知道的:

(1)用 setState() 設置狀態(tài):
this.setState({comment: 'Hello'});
(2)state(狀態(tài)) 更新可能是異步的:

React 為了優(yōu)化性能,有可能會將多個 setState() 調(diào)用合并為一次更新。
因為 this.props 和 this.state 可能是異步更新的,你不能依賴他們的值計算下一個state(狀態(tài))。

例如, 以下代碼可能導致 counter(計數(shù)器)更新失?。?/p>

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

要解決這個問題,應該使用第 2 種 setState() 的格式,它接收一個函數(shù),而不是一個對象。該函數(shù)接收前一個狀態(tài)值作為第 1 個參數(shù), 并將更新后的值作為第 2個參數(shù):

要彌補這個問題,使用另一種 setState() 的形式,它接受一個函數(shù)而不是一個對象。這個函數(shù)將接收前一個狀態(tài)作為第一個參數(shù),應用更新時的 props 作為第二個參數(shù)

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

// 正確
this.setState(function(prevState, props) {
  return {
    counter: prevState.counter + props.increment
  };
});
(3)state(狀態(tài))更新會被合并

當你調(diào)用 setState(), React 將合并你提供的對象到當前的狀態(tài)中。

例如,你的狀態(tài)可能包含幾個獨立的變量:

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

然后通過調(diào)用獨立的 setState() 調(diào)用分別更新它們:
合并是淺合并,所以 this.setState({comments}) 不會改變 this.state.posts 的值,但會完全替換this.state.comments 的值。

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

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

5、數(shù)據(jù)向下流動

無論作為父組件還是子組件,它都無法獲悉一個組件是否有狀態(tài),同時也不需要關心另一個組件是定義為函數(shù)組件還是類組件。

這就是 state(狀態(tài)) 經(jīng)常被稱為 本地狀態(tài) 或 封裝狀態(tài)的原因。 它不能被擁有并設置它的組件 以外的任何組件訪問。

一個組件可以選擇將 state(狀態(tài)) 向下傳遞,作為其子組件的 props(屬性):

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

同樣適用于用戶定義組件:

<FormattedDate date={this.state.date} />

FormattedDate 組件通過 props(屬性) 接收了 date 的值,但它仍然不能獲知該值是來自于 Clock的 state(狀態(tài)) ,還是 Clock 的 props(屬性),或者是直接手動創(chuàng)建的:

function FormattedDate(props) {
  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}

這通常稱為一個“從上到下”,或者“單向”的數(shù)據(jù)流。任何 state(狀態(tài)) 始終由某個特定組件所有,并且從該 state(狀態(tài)) 導出的任何數(shù)據(jù) 或 UI 只能影響樹中 “下方” 的組件。

如果把組件樹想像為 props(屬性) 的瀑布,所有組件的 state(狀態(tài)) 就如同一個額外的水源匯入主流,且只能隨著主流的方向向下流動。

五、處理事件

1、與普通HTML區(qū)別

(1) React 事件使用駝峰命名,而不是全部小寫。
(2)通過 JSX , 你傳遞一個函數(shù)作為事件處理程序,而不是一個字符串。
<button onClick={activateLasers}>
  Activate Lasers
</button>
(3)在 React 中你不能通過返回 false 來阻止默認行為。必須明確調(diào)用 preventDefault 。

例如,對于純 HTML ,要阻止鏈接打開一個新頁面的默認行為,可以這樣寫:

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

在 React 中, 應該這么寫:

function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}
(4)當使用一個 ES6 類定義一個組件時,通常的一個事件處理程序是類上的一個方法。

Toggle 組件渲染一個按鈕,讓用戶在 “ON” 和 “OFF” 狀態(tài)之間切換:

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // 這個綁定是必要的,使`this`在回調(diào)中起作用
    this.handleClick = this.handleClick.bind(this);
  }

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

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

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

2、將參數(shù)傳遞給事件處理程序

在循環(huán)內(nèi)部,通常需要將一個額外的參數(shù)傳遞給事件處理程序。 例如,如果 id 是一個內(nèi)聯(lián) ID,則以下任一方式都可以正常工作:

等價的,分別使用 arrow functions 和 Function.prototype.bind
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

上面兩個例子中,參數(shù) e 作為 React 事件對象將會被作為第二個參數(shù)進行傳遞。通過箭頭函數(shù)的方式,事件對象必須顯式的進行傳遞,但是通過 bind 的方式,事件對象以及更多的參數(shù)將會被隱式的進行傳遞。

六、條件渲染

1、在函數(shù)式組件中用if判斷

我們需要創(chuàng)建一個 Greeting 組件, 用來根據(jù)用戶是否登錄, 判斷并顯示上述兩個組件之一:

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}

ReactDOM.render(
  // 修改為 isLoggedIn={true} 試試:
  <Greeting isLoggedIn={false} />,
  document.getElementById('root')
);

2、元素變量

在接下來的例子中,我們將會創(chuàng)建一個有狀態(tài)組件,叫做 LoginControl 。
它將渲染 <LoginButton /> 或者 <LogoutButton /> ,取決于當前狀態(tài)。同時渲染前面提到的 <Greeting /> 組件:

class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
    this.state = {isLoggedIn: false};
  }

  handleLoginClick() {
    this.setState({isLoggedIn: true});
  }

  handleLogoutClick() {
    this.setState({isLoggedIn: false});
  }

  render() {
    const isLoggedIn = this.state.isLoggedIn;

    let button = null;
    if (isLoggedIn) {
      button = <LogoutButton onClick={this.handleLogoutClick} />;
    } else {
      button = <LoginButton onClick={this.handleLoginClick} />;
    }

    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {button}
      </div>
    );
  }
}

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

3、使用邏輯 && 操作符的內(nèi)聯(lián) if 用法

(1)可以在JSX中嵌入任何表達式,方法是將其包裹在花括號中
function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h1>Hello!</h1>
      {unreadMessages.length > 0 &&
        <h2>
          You have {unreadMessages.length} unread messages.
        </h2>
      }
    </div>
  );
}

const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
  <Mailbox unreadMessages={messages} />,
  document.getElementById('root')
);
(2)條件操作符 condition ? true : false
render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
    </div>
  );
}


render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      {isLoggedIn ? (
        <LogoutButton onClick={this.handleLogoutClick} />
      ) : (
        <LoginButton onClick={this.handleLoginClick} />
      )}
    </div>
  );
}

七、列表(Lists) 和 鍵(Keys)

1、基本列表組件

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li>{number}</li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

2、鍵(Keys)

鍵(Keys) 幫助 React 標識哪個項被修改、添加或者移除了。數(shù)組中的每一個元素都應該有一個唯一不變的鍵(Keys)來標識

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
  <li key={number.toString()}>
    {number}
  </li>
);

const todoItems = todos.map((todo) =>
  <li key={todo.id}>
    {todo.text}
  </li>
);
(1)使用 keys 提取組件

keys 只在數(shù)組的上下文中存在意義。

例如,如果你提取一個 ListItem 組件,應該把 key 放置在數(shù)組處理的 <ListItem /> 元素中,不能放在 ListItem 組件自身中的 <li> 根元素上。

function ListItem(props) {
  // 正確!這里不需要指定 key :
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // 正確!key 應該在這里被指定
    <ListItem key={number.toString()}
              value={number} />

  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);
(2)keys 在同輩元素中必須是唯一的

在數(shù)組中使用的 keys 必須在它們的同輩之間唯一。然而它們并不需要全局唯一。我們可以在操作兩個不同數(shù)組的時候使用相同的 keys

(3)鍵是React的一個內(nèi)部映射,但其不會傳遞給組件的內(nèi)部。

如果你需要在組件中使用相同的值,可以明確使用一個不同名字的 prop 傳入。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • HTML模版 之后出現(xiàn)的React代碼嵌套入模版中。 1. Hello world 這段代碼將一個一級標題插入到指...
    ryanho84閱讀 6,422評論 0 9
  • 本筆記基于React官方文檔,當前React版本號為15.4.0。 1. 安裝 1.1 嘗試 開始之前可以先去co...
    Awey閱讀 7,913評論 14 128
  • 3. JSX JSX是對JavaScript語言的一個擴展語法, 用于生產(chǎn)React“元素”,建議在描述UI的時候...
    pixels閱讀 2,971評論 0 24
  • —— 基礎知識、JSX介紹、React 元素、組件和屬性、狀態(tài)和生命周期 此文檔來自 React 官方文檔,在英文...
    thelastcookies閱讀 523評論 0 1
  • 前不久在微博上看了幾件事,一是警察莫名其妙檢查妙齡女子的身份證,但其并未帶身份證,因此將這兩個女孩拉上警車,...
    小兔子zz閱讀 479評論 0 0

友情鏈接更多精彩內(nèi)容