react 也就這麼回事 05 —— 元件 & Props

蜜瓜發表於2022-03-14

什麼是元件:用來實現區域性功能的可複用程式碼片段

比如很多介面會用到“分頁”功能,因此可以將它封裝成獨立的元件

這樣用到分頁的介面只需引入該元件而不必重新寫程式碼

1 定義元件

在 React 中有兩種元件,一種是函式元件,一種是類元件

1.1 函式元件

定義元件最簡單的方式就是編寫 JavaScript 函式

對 React 來說,能夠返回一個 React 元素的 函式 就叫元件

function MyComponent() {
    return <h2>我是一個函式元件</h2>;
}

線上程式碼

1.2 class 元件

類元件的宣告過程會比較繁瑣一些,需要使用 class、extends 關鍵字,來繼承React.Component{}

render()函式會返回該類的例項要建立的元素。

class MyComponent extends React.Component {
    render() {
        return <h2>我是一個class元件</h2>;
    }
}

線上程式碼

無論是函式元件還是class元件,在 React 中是等效的,不過 class 元件有更多的特性

2 渲染元件

同一個元件在不同介面使用,可能會想要展示不同的內容

比如我們自定義的元件包含了一個h2標籤,如果我們想要在兩個不同的介面分別展示函式class怎麼辦?

可以在使用元件時新增屬性,react 會將新增的屬性轉換為一個物件傳遞給元件,這個物件稱為"props"

函式元件和class元件可以分別通過“形參”和例項屬性來使用這個物件

比如:

function MyComponent(props) {
    console.log(props)
    return <h2>我是一個函式元件</h2>;
}
ReactDOM.render(
    <MyComponent a="1" b="2" />,
    document.getElementById("root")
);
class MyComponent extends React.Component {
    render() {
        console.log(this.props);
        return <h2>我是一個class元件</h2>;
    }
}
ReactDOM.render(
    <MyComponent a="1" b="2" />,
    document.getElementById("root")
);

兩者輸出同樣的物件:

線上程式碼

於是我們可以傳入不同的屬性,來讓元件呈現不同的內容:

function MyComponent(props) {
    return <h2>我是一個{props.name}元件</h2>;
}

ReactDOM.render(
    <MyComponent name="自定義函式" />,
    document.getElementById("root")
);

線上程式碼

這個例子中發生了這些事:

  1. 我們呼叫 ReactDOM.render() 函式,並傳入 <MyComponent name="自定義函式" /> 作為引數。
  2. React 呼叫 MyComponent 元件,並將 {name: '自定義函式'} 作為 props 傳入。
  3. MyComponent 元件將 <h2>我是一個自定義函式元件</h2> 元素作為返回值。
  4. React DOM 將 DOM 高效地更新為 <h2>我是一個自定義函式元件</h2>

3 注意點

  • 元件名稱必須以大寫字母開頭。

  • 傳入屬性值為字串和數字的區別:

    數字:<MyComponent a={1} />

    字串:<MyComponent a="1" />

  • 多個屬性可以使用擴充套件運算子

    const obj = { name: 'React', age: 18 }
    <MyComponent {...obj} /> 
    

    注意{}不能省略

線上程式碼

3 組合元件

元件可以在其輸出中引用其他元件

例如,我們可以建立一個可以多次渲染 Welcome 元件的 App 元件:

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')
);

這就可以讓我們用同一元件來構建不同層次的新元件

線上程式碼

4 提取元件

對於一個複雜的元件,我們應該儘量將其拆分為更小的元件,以提高其可維護性和可讀性

例如,參考如下 Comment 元件:

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <img className="Avatar"
          src={props.author.avatarUrl}
          alt={props.author.name}
        />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

該元件用於描述一個社交媒體網站上的評論功能,它接收 author(物件),text (字串)以及 date(日期)作為 props。

該元件由於巢狀的關係,變得難以維護,且很難複用它的各個部分。因此,讓我們從中提取一些元件出來。

首先,我們將提取 Avatar 元件:

function Avatar(props) {
  return (
    <img className="Avatar"
      src={props.user.avatarUrl}
      alt={props.user.name}
    />
  );
}

Avatar 不需知道它在 Comment 元件內部是如何渲染的。因此,我們給它的 props 起了一個更通用的名字:user,而不是 author

建議從元件自身的角度命名 props,而不是依賴於呼叫元件的上下文命名。

現在可以在Comment中引用Avatar元件了:

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

接下來,我們將提取 UserInfo 元件,該元件在使用者名稱旁渲染 Avatar 元件:

function UserInfo(props) {
  return (
    <div className="UserInfo">
      <Avatar user={props.user} />
      <div className="UserInfo-name">
        {props.user.name}
      </div>
    </div>
  );
}

進一步簡化 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>
  );
}

5 Props 的只讀性

對於 props,React 有一個嚴格的規則:

元件無論是使用函式宣告還是通過 class 宣告,都決不能修改自身的 props。

6 計時器

function tick() {
  const element = (
 		<h2>當前時間: {new Date().toLocaleTimeString()}.</h2>
  );
  ReactDOM.render(element, document.getElementById('root'));
}

setInterval(tick, 1000);

這個例子中,每秒呼叫一次 tick 函式,頁面會更新當前時間

線上程式碼

將它封裝為一個元件:

class Clock extends React.Component {
  render() {
    return <h2>現在時間:{new Date().toLocaleTimeString()}</h2>;
  }
}

function tick() {
  ReactDOM.render(<Clock />, document.getElementById("root"));
}

setInterval(tick, 1000);

我們將時間寫死在了 JSX 中

線上程式碼

如果我們想自己傳入顯示的內容:

class Clock extends React.Component {
  render() {
    const time = this.props.time;
    return <h2>現在時間:{time}</h2>;
  }
}

function tick() {
  ReactDOM.render(
    <Clock time={new Date().toLocaleTimeString()} />,
    document.getElementById("root")
  );
}

setInterval(tick, 1000);

這樣我們就可以控制顯示的格式

線上程式碼

公眾號【前端嘛】

相關文章