React JSX
React 使用 JSX 来替代常规的 JavaScript。
JSX 是一个看起来很像 XML 的 JavaScript 语法扩展。
我们不需要一定使用 JSX,但它有以下优点:
- JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。
- 它是类型安全的,在编译过程中就能发现错误。
- 使用 JSX 编写模板更加简单快速。
我们先看下以下代码:
const element = <h1>Hello, world!</h1>;
这种看起来可能有些奇怪的标签语法既不是字符串也不是 HTML。
它被称为 JSX, 一种 JavaScript 的语法扩展。 我们推荐在 React 中使用 JSX 来描述用户界面。
JSX 是在 JavaScript 内部实现的。
我们知道元素是构成 React 应用的最小单位,JSX 就是用来声明 React 当中的元素。
与浏览器的 DOM 元素不同,React 当中的元素事实上是普通的对象,React DOM 可以确保 浏览器 DOM 的数据内容与 React 元素保持一致。
要将 React 元素渲染到根 DOM 节点中,我们通过把它们都传递给 ReactDOM.render() 的方法来将其渲染到页面上:
React 实例
const element = <h1 className="foo">Hello, world</h1>; const root = ReactDOM.createRoot(document.getElementById("root")); root.render(element);
注意:
由于 JSX 就是 JavaScript,一些标识符像
class和for不建议作为 XML 属性名。作为替代,React DOM 使用className和htmlFor来做对应的属性。
使用 JSX
JSX 看起来类似 HTML ,我们可以看下实例:
const element = <h1 className="foo">Hello, world</h1>; const root = ReactDOM.createRoot(document.getElementById("root")); root.render(element);
我们可以在以上代码中嵌套多个 HTML 标签,需要使用一个 div 元素包裹它,实例中的 p 元素添加了自定义属性 data-myattribute ,添加自定义属性需要使用 data- 前缀。
React 实例
const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <div> <h1>菜鸟教程</h1> <h2>欢迎学习 React</h2> <p data-myattribute = "somevalue">这是一个很不错的 JavaScript 库!</p> </div> );
独立文件
你的 React JSX 代码可以放在一个独立文件上,例如我们创建一个 helloworld_react.js 文件,代码如下:
const element = <h1 className="foo">Hello, world</h1>; const root = ReactDOM.createRoot(document.getElementById("root")); root.render(element);
然后在 HTML 文件中引入该 JS 文件:
React 实例
<body> <div id="example"></div> <script type="text/babel" src="helloworld_react.js"></script> </body>
JavaScript 表达式
我们可以在 JSX 中使用 JavaScript 表达式。表达式写在花括号 {} 中。实例如下:
React 实例
const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <div> <h1>{1+1}</h1> </div> );
在 JSX 中不能使用 if else 语句,但可以使用 conditional (三元运算) 表达式来替代。以下实例中如果变量 i 等于 1 浏览器将输出 true , 如果修改 i 的值,则会输出 false.
React 实例
var i = 1; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <div> <h1>{i == 1 ? 'True!' : 'False'}</h1> </div> );
样式
React 推荐使用内联样式。我们可以使用 camelCase 语法来设置内联样式. React 会在指定元素数字后自动添加 px 。以下实例演示了为 h1 元素添加 myStyle 内联样式:
rogbbs.asus.com.cn/topics/101/feeds/48301
React 实例
var myStyle = { fontSize: 100, color: '#FF0000' }; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <h1 style = {myStyle}>菜鸟教程</h1> );
注释
注释需要写在花括号中,实例如下:
React 实例
const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <div> <h1>菜鸟教程</h1> {/*注释...*/} </div> );
数组
JSX 允许在模板中插入数组,数组会自动展开所有成员:
React 实例
var arr = [ <h1>菜鸟教程</h1>, <h2>学的不仅是技术,更是梦想!</h2>, ]; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <div>{arr}</div> );
React 组件状态(State)
组件可以拥有状态(state),它是组件数据的私有部分,可以用来管理动态数据。
状态仅适用于类组件,或者使用 React 的 Hook 时可以在函数组件中使用。
React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。
React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。
以下实例创建一个名称扩展为 React.Component 的 ES6 类,在 render() 方法中使用 this.state 来修改当前的时间。
添加一个类构造函数来初始化状态 this.state,类组件应始终使用 props 调用基础构造函数。
类组件中的状态管理
创建一个有状态的类组件:
Counter.js 文件
import React, { Component } from 'react';
class Counter extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
export default Counter;
在 src/index.js 中渲染该组件:
实例
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Counter from './Counter';
const root = ReactDOM.createRoot(document.getElementById("root"));
// 渲染 Counter 组件
root.render(<Counter />);
函数组件中的状态管理(使用 Hook)
使用 React Hook 可以在函数组件中使用状态。最常用的 Hook 是 useState。
创建一个有状态的函数组件:
Counter.js 文件
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default Counter;
在 src/index.js 中渲染该组件:
rogbbs.asus.com.cn/topics/101/feeds/48304
实例
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Counter from './Counter';
const root = ReactDOM.createRoot(document.getElementById("root"));
// 渲染 Counter 组件
root.render(<Counter />);
实例
创建一个时间点实例来理解组件状态:
React 实例
接下来,我们将使Clock设置自己的计时器并每秒更新一次。
将生命周期方法添加到类中
在具有许多组件的应用程序中,在销毁时释放组件所占用的资源非常重要。
每当 Clock 组件第一次加载到 DOM 中的时候,我们都想生成定时器,这在 React 中被称为挂载。
同样,每当 Clock 生成的这个 DOM 被移除的时候,我们也会想要清除定时器,这在 React 中被称为卸载。
我们可以在组件类上声明特殊的方法,当组件挂载或卸载时,来运行一些代码:
React 实例
实例解析:
componentDidMount() 与 componentWillUnmount() 方法被称作生命周期钩子。
在组件输出到 DOM 后会执行 componentDidMount() 钩子,我们就可以在这个钩子上设置一个定时器。
this.timerID 为定时器的 ID,我们可以在 componentWillUnmount() 钩子中卸载定时器。
代码执行顺序:
-
当
<Clock />被传递给ReactDOM.render()时,React 调用Clock组件的构造函数。 由于Clock需要显示当前时间,所以使用包含当前时间的对象来初始化this.state。 我们稍后会更新此状态。 -
React 然后调用
Clock组件的render()方法。这是 React 了解屏幕上应该显示什么内容,然后 React 更新 DOM 以匹配Clock的渲染输出。 -
当
Clock的输出插入到 DOM 中时,React 调用componentDidMount()生命周期钩子。 在其中,Clock组件要求浏览器设置一个定时器, -
每秒钟调用一次
tick()。 -
浏览器每秒钟调用
tick()方法。 在其中,Clock组件通过使用包含当前时间的对象调用setState()来调度UI更新。 通过调用setState(),React 知道状态已经改变,并再次调用render()方法来确定屏幕上应当显示什么。 这一次,render()方法中的this.state.date将不同,所以渲染输出将包含更新的时间,并相应地更新 DOM。 -
一旦
Clock组件被从 DOM 中移除,React 会调用componentWillUnmount()这个钩子函数,定时器也就会被清除。
数据自顶向下流动
父组件或子组件都不能知道某个组件是有状态还是无状态,并且它们不应该关心某组件是被定义为一个函数还是一个类。
这就是为什么状态通常被称为局部或封装。 除了拥有并设置它的组件外,其它组件不可访问。
以下实例中 FormattedDate 组件将在其属性中接收到 date 值,并且不知道它是来自 Clock 状态、还是来自 Clock 的属性、亦或手工输入:rogbbs.asus.com.cn/topics/101/feeds/48330
React 实例
这通常被称为自顶向下或单向数据流。 任何状态始终由某些特定组件所有,并且从该状态导出的任何数据或 UI 只能影响树中下方的组件。rogbbs.asus.com.cn/topics/101/feeds/48296
如果你想象一个组件树作为属性的瀑布,rogbbs.asus.com.cn/topics/101/feeds/48299每个组件的状态就像一个额外的水源,它连接在一个任意点,但也流下来。
为了表明所有组件都是真正隔离的,我们可以创建一个 App 组件,它渲染三个Clock:
React 实例
立更新。
在 React 应用程序中,组件是有状态还是无状态被认为是可能随时间而变化的组件的实现细节。
我们可以在有状态组件中使用无状态组件,也可以在无状态组件中使用有状态组件。