Skip to main content

21年11月21日试图学点React

· 8 min read
VisualDust
Ordinary Magician | Half stack developer

Basic JavaScript-rendered Hello World

使用Pure HTML在屏幕上渲染Hello World:

<html>
<body>
<div>Hello World</div>
</body>
</html>

在html的script中,可以通过append的方式向父元素添加子元素:

<body>
<script>
const rootElement = document.createElement('div')
rootElement.id = 'rootElement'
document.body.append(rootElement)

const element1 = document.createElement('div')
const element2 = document.createElement('div')
element1.textContent = 'Hello World'
element2.textContent = new Date()
// element.className='' //whats for?
rootElement.append(element1)
rootElement.append(element2)
</script>
</body>

上述代码向rootElement追加了包含"Hello World"和当前日期文本的div元素。

Intro to raw React APIs

除了使用document.createElement创建元素外,还可以使用React.createElement

note

为了在script块中使用React,需要引用相关的包:

<script src="https://unpkg.zhimg.com/react@17.0.0/umd/react.development.js"></script>
<script src="https://unpkg.zhimg.com/react-dom@17.0.0/umd/react-dom.development.js"></script>

其中unpkg.zhimg.comunpkg.com的国内CDN。

例如:

const element = React.createElement('div', {
className: 'container',
// children:[]
})
note

React 是 React 库的入口。如果你通过使用<script>标签的方式来加载 React,则可以通过 React 全局变量对象来获得 React 的顶层 API

再例如,想要实现:

<body>
<div id="root">
<div class="container">
<span>Hello</span>
<span>World</span>
</div>
</div>
</body>

可以在<script>块中这样写:

const rootElement = document.getElementById('root')
const sube1 = React.createElement('span',null,'Hello')
const sube2 = React.createElement('span',null,'World')
const element = React.createElement('div', {
className: 'container',
// children:[]
},sube1,' ',sube2)
ReactDOM.render(element,rootElement) //use render.

注意,将children直接追加在属性之后和单独在属性中使用children key来添加是等效的。也就是说,下面这两种方式是等效的:

const element = React.createElement('div', {
className: 'container',
// children:[]
},sube1,' ',sube2)
note

上述写法属于不使用 JSX 的 React。React 并不强制要求使用 JSX。

Using JSX

设想如下变量声明:

const element = <div className="container">Hello World</div>

这个有趣的标签语法既不是字符串也不是 HTML。它被称为 JSX,是一个 JavaScript 的语法扩展。我们建议在 React 中配合使用 JSX,JSX 可以很好地描述 UI 应该呈现出它应有交互的本质形式。JSX 可能会使人联想到模板语言,但它具有 JavaScript 的全部功能。JSX 可以生成 React “元素”。

如果打印其类型和内容,会得到:

console.log(typeof(element))
console.log(element)

这和之前使用createElement产生的内容完全相同。

note

React 认为渲染逻辑本质上与其他 UI 逻辑内在耦合,比如,在 UI 中需要绑定处理事件、在某些时刻状态发生变化时需要通知到 UI,以及需要在 UI 中展示准备好的数据。

React 并没有采用将标记与逻辑进行分离到不同文件这种人为地分离方式,而是通过将二者共同存放在称之为“组件”的松散耦合单元之中,来实现关注点分离。我们将在后面章节中深入学习组件。如果你还没有适应在 JS 中使用标记语言,这个会议讨论应该可以说服你。

React 不强制要求使用 JSX,但是大多数人发现,在 JavaScript 代码中将 JSX 和 UI 放在一起时,会在视觉上有辅助作用。它还可以使 React 显示更多有用的错误和警告消息。

在JSX中,可以直接嵌入表达式:

const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;
note

JSX 也是一个表达式。在编译之后,JSX 表达式会被转为普通 JavaScript 函数调用,并且对其取值后得到 JavaScript 对象。也就是说,你可以在 if 语句和 for 循环的代码块中使用 JSX,将 JSX 赋值给变量,把 JSX 当作参数传入,以及从函数中返回 JSX:

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

在html的script块中书写JSX,需要引用:

<script src="https://unpkg.zhimg.com/@babel/standalone@7.12.4/babel.js"></script>

并且还需要修改script块的type:

<script type="text/babel">
warning

这样做只是为了方便,但请不要在production环境中使用这种方法。这可能导致部分源码泄漏。

使用JSX和不使用JSX可以创造等效的代码。例如:下面的两段代码是等效的:

class Hello extends React.Component {
render() {
return <div>Hello {this.props.toWhat}</div>;
}
}

ReactDOM.render(
<Hello toWhat="World" />,
document.getElementById('root')
);
note

每个 JSX 元素只是调用 React.createElement(component, props, ...children) 的语法糖。因此,使用 JSX 可以完成的任何事情都可以通过纯 JavaScript 完成。

在JSX中,可以使用大括号传递变量:

  const children = 'Hello World'
const className = 'container'
const props = {className, children}
const element = <div className={props.className}>{props.children}</div>

当你想传递的props比较长的时候,把它们挨个写上可不是什么方便的做法。所以,你可以这样写:

const children = 'Hello World'
const className = 'container'
const props = {className, children}
const element = React.createElement('div',{props})

上述代码中的React.createElement也可以替换为JSX语法:

const children = 'Hello World'
const className = 'container'
const props = {className, children}
const element = <div {...props}/>
warning
上述代码
const element = <div {...props}/>

中的...不可以省略。

除此之外,你可以将props当作一个“扩充”:

const children = 'Hello World'
const className = 'container'
const props = {className, children}
const element = <div {id:'my-id',...props} />

注意,这里的先后顺序影响谁会生效。例如,下面的两种顺序会导致className不一样:

  const children = 'Hello World'
const className = 'container'
const props = {className, children}
const element = React.createElement('div',{id:'my-id',className:'whatever',...props})
// 最终生效的 className 会是 container

可以看出,相同的属性,顺序在后面的会生效。