昨天我们提到了该如何撰写 JSX,今天就来学习怎麽建立元件,来把同类型的 React element 做抽象化吧~
通常在写 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>
)
先来看一下上面范例的结构:
<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)
由於之前测试的前端中台模板 Antd 都是跟别人借大陆那边的工厂 IP 做测试 , 今天在办公室以及...
前面几篇文章我们大部份都是在讨论 : 集中式架构如何的分层 但应该有不少人注意到,我们是专注在每一层...
第五天的文章就来谈谈工作上学习到的切版画面 首先一样附上范例图: 这是常见的登入会员或是加入会员的页...
列表移动过渡(List move transition) 不仅可以做出淡出与淡入,还可以改变位置,只...
今天练了一下二维阵列 利用scanf将输入的数值与自己相乘後,并将结果反着印出,最後一个输入的数值第...