Re: 新手让网页 act 起来: Day05 - 建立元件

昨天我们提到了该如何撰写 JSX,今天就来学习怎麽建立元件,来把同类型的 React element 做抽象化吧~

Function Component

通常在写 code 的时候,如果遇到重复性很高的程序码,往往会用函式把它包起来,等有需要这程序码的时候再呼叫函式使用它,来避免一直写重复的 code。

那在 React 中,也是同样的道理,我们可以将重复性很高的 UI 结构,抽象化成一个元件,当要使用的时候丢资料进去就好。以下用简单的例子示范:

<html lang="en">
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>

<body>
  <div id='root'></div>
  <script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
  <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
  <script src="https://unpkg.com/@babel/[email protected]/babel.js"></script>

  <script type='text/babel'>
    const message = (props) => {
      return <div>{props.children}</div>
    }

    const element = (
      <div className='container'>
        {message({children: 'Black cat'})}
        {message({children: 'Orange dog'})}
      </div>
    )

    ReactDOM.render(element, document.getElementById('root'))
  </script>
</body>

</html>


顺利的话,就能在画面上看到两行 message。不过其实真正在写的时候不会这样做。不知道大家有没有印象,在最一开始介绍 React.createElement 的时候第一个参数接收 type,其实这个 type 可以接收一个会回传一个 React element 的函式。让我们将上面的程序码改写一下。

const message = (props) => {
  return <div>{props.children}</div>
}

const element = (
  <div className='container'>
    {React.createElement(message, {}, 'Black cat')}
    {message({ children: 'Orange dog' })}
  </div>
)

这个时候大家可能会好奇,结果不是都一样,为什麽还要这样改写?看起来结果的确都一样,但是如果 chorme 有安装 react devtool ,打开它之後就会发现两者呈现的结构会是不一样的。

接下来再让我们更近一步,既然我们能够写成 React.createElemnt 的形式,那我们是不是也能够写成 JSX 呢? 现来让我们复习一下,一般产生 div 会是怎麽样子:

const jsEl = React.createElement('div', {}, 'hello world')

const jsxEl = <div>hello world</div>

仔细观察一下规则,可以猜测第一个参数 'div',最终就会是 JSX tag 的名称,所以我们可以再改写成这样:

const message = (props) => {
  return <div>{props.children}</div>
}

const element = (
  <div className='container'>
    <message>black cat</message>
    {React.createElement(message, {}, 'Orange dog')}
  </div>
)

这个时候看一下画面,会发现好像成功了,但 console 却有错误跑出来,并贴心的告诉我们浏览器看不懂 ,可以将 m 换成大写。这是什麽原因呢?这个时候再去打开 head 中的 script 就会发现 Babel 转换成的结果会是

React.createElemnet('message', null, 'black cat')

但其实我们希望的结果是像第二个那样子,是一个 fuction expression,所以如果我们想要将元件写成 JSX 形式,第一个字母要大写,那 Babel 才会知道 ,「 喔!原来是传入一个 function 进来啊!」。 所以我们只要把 function 名称改成大写就不会喷错了。

const Message = ({ children }) => {
  return <div>{children}</div>
}

const element = (
  <div className='container'>
    <Message>black cat</Message>
    <Message>orange dog</Message>
  </div>
)

React Fragments

先来看一下上面范例的结构:

<div id='root'>
  <div className='container'>
    <div>black cat</div>    
    <div>orange dog</div>    
  </div>
</div>

如果说,我们不想要 container 的话,ㄧ般来说就是直接把那个 div 删除。但当我们尝试这样子做,会造成语法上的错。

const Message = ({ children }) => {
  return <div>{children}</div>
}

const element = (
    <Message>black cat</Message>
    <Message>orange dog</Message>
)

因为我们不会想要同时塞两个值到同个变数中。这个时候我们就可以使用 React.Fragment 来帮我们处理这个问题。可以把它想像成一个隐形的容器帮我们把 React element 装起来。

const Message = ({ children }) => {
  return <div>{children}</div>
}

const element = (
  <React.Fragment>
    <Message>black cat</Message>
    <Message>orange dog</Message>
  </React.Fragment>
)

最後,如果想要偷懒写少一点字,其实可以改成这样就好,结果会是一样的。

const element = (
  <>
    <Message>black cat</Message>
    <Message>orange dog</Message>
  </>
)

以上就是今天的介绍,有什麽问题都欢迎在下方留言。


<<:  [Tableau Public] day 20:制作第三张仪表板

>>:  day5: CSS style 规划 CSS module (global CSS, CSS module)

【Day11】前端环境重设之工作流水帐

由於之前测试的前端中台模板 Antd 都是跟别人借大陆那边的工厂 IP 做测试 , 今天在办公室以及...

30-24 之从集中式架构到微服务的难点 - DDD 的诞生

前面几篇文章我们大部份都是在讨论 : 集中式架构如何的分层 但应该有不少人注意到,我们是专注在每一层...

33岁转职者的前端笔记-DAY 5 登入画面切版实作

第五天的文章就来谈谈工作上学习到的切版画面 首先一样附上范例图: 这是常见的登入会员或是加入会员的页...

Day21 样式变化(动画)5

列表移动过渡(List move transition) 不仅可以做出淡出与淡入,还可以改变位置,只...

Day13-"练习二维阵列"

今天练了一下二维阵列 利用scanf将输入的数值与自己相乘後,并将结果反着印出,最後一个输入的数值第...