1. 程式人生 > >react(4) React不同條件渲染出不同效果

react(4) React不同條件渲染出不同效果

React 中的條件渲染有以下幾種方式:

  • if 語句
  • 三元操作符(ternary operator)
  • 邏輯 && 操作符
  • switch.. case.. 語句
  • 列舉(enums)
  • 多層條件渲染(multi-level conditional reandering)
  • 使用高階元件

1.if 語句

在React中使用if語句條件渲染是最簡單的。比如List元件如果沒有任何items,可以提前return

function List({ list }) {
  if (!list) {
    return null;
  }
  return (
    <div>
      {list.map(item => <ListItem item={item} />)}
    </div>
  );
}

一個元件如果return null,將不會被渲染出來。如果你想給使用者一些反饋,當list為空時,可以採用下面方式:

function List({ list }) {
  // list 為null的情況
  if (!list) {
    return null;
  }

  // list 為空的情況
  if (!list.length) {
    return <p>sorry, the list is empty</p>
  } else {
    return (
      <div>
        {list.map(item => <ListItem item={item} />)}
      </div>
    );
  }
}

if...else 是最基本的條件渲染方式。

2.三元操作符

可以使用三元運算子來代替上面的if...else... 條件渲染。

例如,你想從2種模式(edit, view)中切換,可以使用布林值來決定那個元件被渲染:

function Item({ item, mode }) {
  const isEditMode = mode === 'EDIT';

  return (
    <div>
      { isEditMode
          ? <ItemEdit item={item} />
          : <ItemView item={item}>
      }
    </div>
  );
}

三元運算子使條件渲染更加的簡潔,使得程式碼可以採用內聯(inline)的方式表達出來

3.邏輯 '&&' 操作符

這個是當你想渲染一個元件或者什麼也不渲染的情況

例如,有一個 LoadingIndicator 元件,返回載入文字或者什麼也沒有。當然可以使用if...else或者三元運算子,如下:

function LoadingIndicator({ isLoading }) {
  if (isLoading) {
    return (
      <div>
        <p>Loading...</p>
      </div>
    );
  } else {
    return null;
  }
}

function LoadingIndicator({ isLoading }) {
  return (
    <div>
      { isLoading
          ? <p>Loading...</p>
          : null
      }
    </div>
  );
}

使用 && 可以使返回 null 的情況的條件渲染更加的簡潔

function LoadingIndicator({ isLoading }) {
  return (
    <div>
      { isLoading && <p>Loading...</p> }
    </div>
  );
}

4.switch...case語句

我們有可能遇到多種條件渲染的情況,例如依據不同的state渲染不同的Component.

例如,Notification 元件根據輸入狀態可能渲染Error,Warning,Info三種不同的元件。這個時候可以使用switch...case來進行多種條件渲染:

function Notification({ text, state }) {
  switch (state) {
    case 'info':
      return <Info text={text} />;
    case 'warning':
      return <Warning text={text} />;
    case 'info':
      return <Info text={text} />;
    default:
      return null;
  }
}

注意switch...case語句永遠要加上default情況,因為React元件要麼返回元素,要麼返回null

另外值得注意的是,如果元件依據 state 屬性 渲染時,最後新增上 React.PropTypes,即上面的元件後面新增:

Notification.propTypes = {
  text: React.PropTypes.string,
  state: React.PropTypes.oneOf(['info', 'warning', 'error'])
}

另一種將條件渲染結果內聯在switch...case中的方法是,使用立即呼叫函式

function Notification({ text, state }) {
  return (
    <div>
      {(() => {
          switch (state) {
            case 'info':
              return <Info text={text} />;
            case 'warning':
              return <Warning text={text} />;
            case 'info':
              return <Info text={text} />;
            default:
              return null;
          }
      })()}
    </div>  
  );
}

switch...case幫助我們在多種條件中渲染中使用,但是多種條件渲染最好的方式是列舉

5.列舉(Enums)

在javascript中,物件的鍵值對可以用作列舉:

const ENUM = {
  a: '1',
  b: '2',
  c: '3'
};

列舉是多種條件渲染中很好的一種方式,上面的 Notification 元件可以寫為:

function Notification({ text, state }) {
  return (
    <div>
      {{
        info: <Info text={text} />,
        warning: <Warning text={text} />,
        error: <Error text={text} />
      }[state]}
    </div>
  )
}

上面的 state 屬性用於取回物件中的值,這比switch...case可讀性更強。

因為物件的值依賴 text 屬性,所以我們必須使用內聯物件。如果我們不需要text屬性,我們可以使用外部靜態列舉:

const NOTIFICATION_STATES = {
  info: <Infor />,
  warning: <Warning />,
  error: <Error />,
};

function Notification({ state }) {
  return (
    <div>
      {NOTIFICATION_STATES[state]}
    </div>
  )
}

如果我們需要text屬性,我們可以使用函式取回物件的值

const getSpecificNotification = (text) => ({
  info: <Info text={text} />,
  warning: <Warning text={text} />,
  error: <Error text={text} />,
});

function Notification({ state, text }) {
  return (
    <div>
      {getSpecificNotification(text)[state]}
    </div>  
  )
}

物件用作列舉,使用場景很靈活,下面例子:

function FooBarOrFooOrBar({ isFoo, isBar }) {
  const key = `${isFoo}-${isBar}`;
  return (
    <div>
      {{
        ['true-true']: <FooBar />,
        ['true-false']: <Foo />,
        ['false-true']: <Bar />,
        ['false-false']: null,
      }[key]}
    </div>
  );
}
FooBarOrFooOrBar.propTypes = {
  isFoo: React.PropTypes.boolean.isRequired,
  isBar: React.PropTypes.boolean.isRequired
}

6.多層條件渲染

我們有時候可能碰到巢狀條件選擇渲染的情況。

例如,List元件可能顯示一個list,或者一個empty text提示,或者什麼多沒有:

function List({ list }) {
  const isNull = !list;
  const isEmpty = !isNull && !list.length;

  return (
    <div>
      { isNull
          ? null
          : ( isEmpty
              ? <p>Sorry, the list is empty</p>
              : <div>{list.map(item => <ListItem item={item} />)}</div>
          )
      }
    </div>
  );
}

// 例項
<List list={null} /> // <div></div>
<List list={[]} /> // <div><p>Sorry, the list is empty</p></div>
<List list={['a', 'b', 'c']} /> // <div><div>a</div><div>b</div><div>c</div></div>

但是最好保持巢狀的層數最小化,這樣程式碼可讀性更強。可以將元件劃分成更小的元件的方式

function List({ list }) {
  const isList = list && list.length;

  return (
    <div>
      { isList
          ? <div>{list.map(item => <ListItem item={item} />)}</div>
          : <NoList isNull={!list} isEmpty={list && !list.empty} />
      }
    </div>
  );
}

function NoList({ isNull, isEmpty }) {
  return (!isNull && isEmpty) && <p>Sorry, the list is empty</p>
}

7.高階元件用作條件渲染

HOCs 在React中很適合條件渲染。HOCs的一種使用方式就是改變元件的外觀。

例如使用高階元件來展示一個載入顯示器或者一個想要的元件:

function withLoadingIndicator(Component) {
  return function EnhancedComponent({ isLoading, ...props }) {
    if (!isLoading) {
      return <Component { ...props } />;
    }

    return <div><p>Loading...</p></div>;
  }
}

// 使用
const ListWithLoadingIndicator = withLoadingIndicator(List);

<ListWithLoadingIndicator
  isLoading={props.isLoading}
  list={props.list}
/>

這個示例中,List元件能關注渲染list上,而不必擔心loading狀態,另外,HOCs可以遮蔽list為null或empty的情況。

總結

使用上面的哪一種條件渲染可以根據下面的一些情況而定:

  • if-else

    • 最簡單的條件渲染
    • 適用於新手
    • 使用if,從渲染方法中返回null提前退出函式
  • 三元操作符

    • 比if-else更好,優先使用
    • 比if-else更加簡潔
  • 邏輯 '&&' 操作符

    • 不返回元素就返回null時使用
  • switch...case

    • 比較冗長
    • 可以通過立即呼叫函式內聯使用
    • 使用列舉的方式代替這種方式更好
  • 列舉(enums)

    • 使用於不同的狀態使用
    • 超過一種條件選擇時使用
  • 多層次條件選擇渲染

    • 避免使用這種方式對可讀性的影響
    • 將元件劃分為更小的元件,小元件自身帶有條件選擇
    • 偏向於使用高階元件(HOCs)
  • HOCs

    • 使用高階元件而遮蔽條件渲染
    • 元件能關注主要的邏輯目的