21年11月21日试图学点React
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
。
为了在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.com
是unpkg.com
的国内CDN。
例如:
const element = React.createElement('div', {
className: 'container',
// children:[]
})
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来添加是等效的。也就是说,下面这两种方式是等效的:
- 方式 1
- 方式 2
const element = React.createElement('div', {
className: 'container',
// children:[]
},sube1,' ',sube2)
const element = React.createElement('div', {
className: 'container',
children:[sube1,' ',sube2]
})
上述写法属于不使用 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)
object
{$$typeof: Symbol(react.element), type: 'div', key: null, ref: null, props: {…}, …}
这和之前使用createElement产生的内容完全相同。
React 认为渲染逻辑本质上与其他 UI 逻辑内在耦合,比如,在 UI 中需要绑定处理事件、在某些时刻状态发生变化时需要通知到 UI,以及需要在 UI 中展示准备好的数据。
React 并没有采用将标记与逻辑进行分离到不同文件这种人为地分离方式,而是通过将二者共同存放在称之为“组件”的松散耦合单元之中,来实现关注点分离。我们将在后面章节中深入学习组件。如果你还没有适应在 JS 中使用标记语言,这个会议讨论应该可以说服你。
React 不强制要求使用 JSX,但是大多数人发现,在 JavaScript 代码中将 JSX 和 UI 放在一起时,会在视觉上有辅助作用。它还可以使 React 显示更多有用的错误和警告消息。
在JSX中,可以直接嵌入表达式:
const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;
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">
这样做只是为了方便,但请不要在production环境中使用这种方法。这可能导致部分源码泄漏。
使用JSX和不使用JSX可以创造等效的代码。例如:下面的两段代码是等效的:
- 使用JSX
- 不使用JSX
class Hello extends React.Component {
render() {
return <div>Hello {this.props.toWhat}</div>;
}
}
ReactDOM.render(
<Hello toWhat="World" />,
document.getElementById('root')
);
class Hello extends React.Component {
render() {
return React.createElement('div', null, `Hello ${this.props.toWhat}`);
}
}
ReactDOM.render(
React.createElement(Hello, {toWhat: 'World'}, null),
document.getElementById('root')
);
每个 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>
const element = <div className="container">Hello World</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}/>
上述代码
const element = <div {...props}/>
中的...
不可以省略。
除此之外,你可以将props当作一个“扩充”:
- 使用JSX
- 不使用JSX
const children = 'Hello World'
const className = 'container'
const props = {className, children}
const element = <div {id:'my-id',...props} />
const children = 'Hello World'
const className = 'container'
const props = {className, children}
const element = React.createElement('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
const children = 'Hello World'
const className = 'container'
const props = {className, children}
const element = React.createElement('div',{id:'my-id',...props, className:'whatever'})
// 最终生效的 className 会是 whatever
可以看出,相同的属性,顺序在后面的会生效。