react

声明式,高效且灵活地用于构建用户界面的JS库。使用react可以将一些简短、独立的代码片段组合成复杂的UI界面,这些代码片段被称作组件

helloworld

  1. ReactDOM.render(
  2. <h1>Hello, world!</h1>,
  3. document.getElementById('root')
  4. );

JSX

  1. const element = <h1>Hello, world!</h1>;

这个有趣的标签语法既不是字符串也不是 HTML。
它被称为 JSX,是一个 JavaScript 的语法扩展。
JSX 可以生成 React “元素”。

在JSX中嵌入表达式

在下面的例子中,我们声明了一个名为 name 的变量,然后在 JSX 中使用它,并将它包裹在大括号中:

  1. const name = 'Josh Perez';
  2. const element = <h1>Hello, {name}</h1>;
  3. ReactDOM.render(
  4. element,
  5. document.getElementById('root')
  6. );

在下面的示例中,我们将调用 JavaScript 函数 formatName(user) 的结果,并将结果嵌入到 <h1> 元素中。

  1. function formatName(user) {
  2. return user.firstName + ' ' + user.lastName;
  3. }
  4. const user = {
  5. firstName: 'Harper',
  6. lastName: 'Perez'
  7. };
  8. const element = (
  9. <h1>
  10. Hello, {formatName(user)}!
  11. </h1>
  12. );
  13. ReactDOM.render(
  14. element,
  15. document.getElementById('root')
  16. );

JSX特定属性

你可以通过使用引号,来将属性值指定为字符串字面量:

  1. const element = <div tabIndex="0"></div>;

也可以使用大括号,来在属性值中插入一个 JavaScript 表达式:

  1. const element = <img src={user.avatarUrl}></img>;

使用JSX指定子元素

假如一个标签里面没有内容,你可以使用 /> 来闭合标签,就像 XML 语法一样:

  1. const element = <img src={user.avatarUrl} />;

JSX 标签里能够包含很多子元素:

  1. const element = (
  2. <div>
  3. <h1>Hello!</h1>
  4. <h2>Good to see you here.</h2>
  5. </div>
  6. );

JSX表示对象

Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用。
以下两种示例代码完全等效:

  1. const element = (
  2. <h1 className="greeting">
  3. Hello, world!
  4. </h1>
  5. );
  1. const element = React.createElement(
  2. 'h1',
  3. {className: 'greeting'},
  4. 'Hello, world!'
  5. );

React.createElement() 会预先执行一些检查,以帮助你编写无错代码,但实际上它创建了一个这样的对象:

  1. // 注意:这是简化过的结构
  2. const element = {
  3. type: 'h1',
  4. props: {
  5. className: 'greeting',
  6. children: 'Hello, world!'
  7. }
  8. };

这些对象被称为 “React 元素”。它们描述了你希望在屏幕上看到的内容。React 通过读取这些对象,然后使用它们来构建 DOM 以及保持随时更新。

元素渲染

元素是构成react应用的最小砖块

元素描述了你再屏幕上想看到的内容

  1. const element = <h1>Hello, world</h1>;

与浏览器的 DOM 元素不同,React 元素是创建开销极小的普通对象。React DOM 会负责更新 DOM 来与 React 元素保持一致。

将一个元素渲染成dom

假设你的 HTML 文件某处有一个 <div>

  1. <div id="root"></div>

我们将其称为“根” DOM 节点,因为该节点内的所有内容都将由 React DOM 管理。
仅使用 React 构建的应用通常只有单一的根 DOM 节点。如果你在将 React 集成进一个已有应用,那么你可以在应用中包含任意多的独立根 DOM 节点。
想要将一个 React 元素渲染到根 DOM 节点中,只需把它们一起传入 ReactDOM.render()

  1. const element = <h1>Hello, world</h1>;
  2. ReactDOM.render(element, document.getElementById('root'));

页面上会展示出 “Hello, world”。

更新已渲染的元素

React 元素是不可变对象。一旦被创建,你就无法更改它的子元素或者属性。一个元素就像电影的单帧:它代表了某个特定时刻的 UI。
根据我们已有的知识,更新 UI 唯一的方式是创建一个全新的元素,并将其传入 ReactDOM.render()

考虑一个计时器的例子:

  1. function tick() {
  2. const element = (
  3. <div>
  4. <h1>Hello, world!</h1>
  5. <h2>It is {new Date().toLocaleTimeString()}.</h2>
  6. </div>
  7. );
  8. ReactDOM.render(element, document.getElementById('root'));}
  9. setInterval(tick, 1000);

react只更新它需要更新的部分

组件&Props

组件允许将UI拆分成独立可复用的代码片段,并对每个片段进行独立构思

函数组件与class组件

定义组件最简单的方式就是编写 JavaScript 函数:

  1. function Welcome(props) {
  2. return <h1>Hello, {props.name}</h1>;
  3. }

该函数是一个有效的 React 组件,因为它接收唯一带有数据的 “props”(代表属性)对象与并返回一个 React 元素。这类组件被称为“函数组件”,因为它本质上就是 JavaScript 函数。

同时还可以使用 ES6 的 class 来定义组件:

  1. class Welcome extends React.Component {
  2. render() {
  3. return <h1>Hello, {this.props.name}</h1>;
  4. }
  5. }

上述两个组件在 React 里是等效的。

渲染组件

之前,我们遇到的 React 元素都只是 DOM 标签:

  1. const element = <div />;

不过,React 元素也可以是用户自定义的组件:

  1. const element = <Welcome name="Sara" />;

当 React 元素为用户自定义组件时,它会将 JSX 所接收的属性(attributes)以及子组件(children)转换为单个对象传递给组件,这个对象被称之为 “props”。

例如,这段代码会在页面上渲染 “Hello, Sara”:

  1. function Welcome(props) {
  2. return <h1>Hello, {props.name}</h1>;
  3. }
  4. const element = <Welcome name="Sara" />;
  5. ReactDOM.render(
  6. element,
  7. document.getElementById('root')
  8. );

组合组件

组件可以在其输出中引用其他组件。这就可以让我们用同一组件来抽象出任意层次的细节。按钮,表单,对话框,甚至整个屏幕的内容:在 React 应用程序中,这些通常都会以组件的形式表示。
例如,我们可以创建一个可以多次渲染 Welcome 组件的 App 组件:

  1. function Welcome(props) {
  2. return <h1>Hello, {props.name}</h1>;
  3. }
  4. function App() {
  5. return (
  6. <div>
  7. <Welcome name="Sara" />
  8. <Welcome name="Cahal" />
  9. <Welcome name="Edite" />
  10. </div>
  11. );
  12. }
  13. ReactDOM.render(
  14. <App />,
  15. document.getElementById('root')
  16. );

通常来说,每个新的 React 应用程序的顶层组件都是 App 组件。但是,如果你将 React 集成到现有的应用程序中,你可能需要使用像 Button 这样的小组件,并自下而上地将这类组件逐步应用到视图层的每一处。

提取组件

将组件拆分为更小的组件。
例如,参考如下 Comment 组件:

  1. function Comment(props) {
  2. return (
  3. <div className="Comment">
  4. <div className="UserInfo">
  5. <img className="Avatar"
  6. src={props.author.avatarUrl}
  7. alt={props.author.name}
  8. />
  9. <div className="UserInfo-name">
  10. {props.author.name}
  11. </div>
  12. </div>
  13. <div className="Comment-text">
  14. {props.text}
  15. </div>
  16. <div className="Comment-date">
  17. {formatDate(props.date)}
  18. </div>
  19. </div>
  20. );
  21. }

该组件用于描述一个社交媒体网站上的评论功能,它接收 author(对象),text (字符串)以及 date(日期)作为 props。
该组件由于嵌套的关系,变得难以维护,且很难复用它的各个部分。因此,让我们从中提取一些组件出来。
首先,我们将提取 Avatar 组件:

  1. function Avatar(props) {
  2. return (
  3. <img className="Avatar"
  4. src={props.user.avatarUrl}
  5. alt={props.user.name}
  6. /> );
  7. }

Avatar 不需知道它在 Comment 组件内部是如何渲染的。因此,我们给它的 props 起了一个更通用的名字:user,而不是 author
我们建议从组件自身的角度命名 props,而不是依赖于调用组件的上下文命名。
我们现在针对 Comment 做些微小调整:

  1. function Comment(props) {
  2. return (
  3. <div className="Comment">
  4. <div className="UserInfo">
  5. <Avatar user={props.author} />
  6. <div className="UserInfo-name">
  7. {props.author.name}
  8. </div>
  9. </div>
  10. <div className="Comment-text">
  11. {props.text}
  12. </div>
  13. <div className="Comment-date">
  14. {formatDate(props.date)}
  15. </div>
  16. </div>
  17. );
  18. }

接下来,我们将提取 UserInfo 组件,该组件在用户名旁渲染 Avatar 组件:

  1. function UserInfo(props) {
  2. return (
  3. <div className="UserInfo">
  4. <Avatar user={props.user} />
  5. <div className="UserInfo-name">
  6. {props.user.name}
  7. </div>
  8. </div> );
  9. }

进一步简化 Comment 组件:

  1. function Comment(props) {
  2. return (
  3. <div className="Comment">
  4. <UserInfo user={props.author} />
  5. <div className="Comment-text">
  6. {props.text}
  7. </div>
  8. <div className="Comment-date">
  9. {formatDate(props.date)}
  10. </div>
  11. </div>
  12. );
  13. }

State & 生命周期

通过调用 ReactDOM.render() 来修改我们想要渲染的元素:

  1. function tick() {
  2. const element = (
  3. <div>
  4. <h1>Hello, world!</h1>
  5. <h2>It is {new Date().toLocaleTimeString()}.</h2>
  6. </div>
  7. );
  8. ReactDOM.render(
  9. element,
  10. document.getElementById('root')
  11. );
  12. }
  13. setInterval(tick, 1000);

通过clock组件可以设置计时器进行组件更新
我们可以从封装时钟的外观开始:

  1. function Clock(props) {
  2. return (
  3. <div>
  4. <h1>Hello, world!</h1>
  5. <h2>It is {props.date.toLocaleTimeString()}.</h2>
  6. </div> );
  7. }
  8. function tick() {
  9. ReactDOM.render(
  10. <Clock date={new Date()} />,
  11. document.getElementById('root')
  12. );
  13. }
  14. setInterval(tick, 1000);

然而,它忽略了一个关键的技术细节:Clock 组件需要设置一个计时器,并且需要每秒更新 UI。
理想情况下,我们希望只编写一次代码,便可以让 Clock 组件自我更新:

  1. ReactDOM.render(
  2. <Clock />, document.getElementById('root')
  3. );

我们需要在 Clock 组件中添加 “state” 来实现这个功能。
State 与 props 类似,但是 state 是私有的,并且完全受控于当前组件。

将函数组件转换成class组件

通过以下五步将 Clock 的函数组件转成 class 组件:

  1. 创建一个同名的 ES6 class,并且继承于 React.Component
  2. 添加一个空的 render() 方法。
  3. 将函数体移动到 render() 方法之中。
  4. render() 方法中使用 this.props 替换 props
  5. 删除剩余的空函数声明。
  1. class Clock extends React.Component {
  2. render() {
  3. return (
  4. <div>
  5. <h1>Hello, world!</h1>
  6. <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
  7. </div>
  8. );
  9. }
  10. }

现在 Clock 组件被定义为 class,而不是函数。
每次组件更新时 render 方法都会被调用,但只要在相同的 DOM 节点中渲染 <Clock /> ,就仅有一个 Clock 组件的 class 实例被创建使用。这就使得我们可以使用如 state 或生命周期方法等很多其他特性。

TODO

事件处理

react元素的事件处理和DOM元素的很相似,但有一点语法上的不同

  • React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
  • 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

例如,传统的 HTML:

  1. <button onclick="activateLasers()">
  2. Activate Lasers
  3. </button>

在 React 中略微不同:

  1. <button onClick={activateLasers}>
  2. Activate Lasers
  3. </button>

在 React 中另一个不同点是你不能通过返回 false 的方式阻止默认行为。你必须显式的使用 preventDefault 。例如,传统的 HTML 中阻止链接默认打开一个新页面,你可以这样写:

  1. <a href="#" onclick="console.log('The link was clicked.'); return false">
  2. Click me
  3. </a>

在 React 中,可能是这样的:

  1. function ActionLink() {
  2. function handleClick(e) {
  3. e.preventDefault();
  4. console.log('The link was clicked.');
  5. }
  6. return (
  7. <a href="#" onClick={handleClick}>
  8. Click me
  9. </a>
  10. );
  11. }

在这里,e 是一个合成事件。

使用 React 时,你一般不需要使用 addEventListener 为已创建的 DOM 元素添加监听器。事实上,你只需要在该元素初始渲染的时候添加监听器即可。
当你使用 ES6 class 语法定义一个组件的时候,通常的做法是将事件处理函数声明为 class 中的方法。例如,下面的 Toggle 组件会渲染一个让用户切换开关状态的按钮:

  1. class Toggle extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.state = {isToggleOn: true};
  5. // 为了在回调中使用 `this`,这个绑定是必不可少的
  6. this.handleClick = this.handleClick.bind(this);
  7. }
  8. handleClick() {
  9. this.setState(state => ({
  10. isToggleOn: !state.isToggleOn
  11. }));
  12. }
  13. render() {
  14. return (
  15. <button onClick={this.handleClick}>
  16. {this.state.isToggleOn ? 'ON' : 'OFF'}
  17. </button>
  18. );
  19. }
  20. }
  21. ReactDOM.render(
  22. <Toggle />,
  23. document.getElementById('root')
  24. );

你必须谨慎对待 JSX 回调函数中的 this,在 JavaScript 中,class 的方法默认不会绑定 this。如果你忘记绑定 this.handleClick 并把它传入了 onClick,当你调用这个函数的时候 this 的值为 undefined
这并不是 React 特有的行为;这其实与 JavaScript 函数工作原理有关。通常情况下,如果你没有在方法后面添加 (),例如 onClick={this.handleClick},你应该为这个方法绑定 this
如果觉得使用 bind 很麻烦,这里有两种方式可以解决。如果你正在使用实验性的 public class fields 语法,你可以使用 class fields 正确的绑定回调函数:

  1. class LoggingButton extends React.Component {
  2. // 此语法确保 `handleClick` 内的 `this` 已被绑定。
  3. // 注意: 这是 *实验性* 语法。
  4. handleClick = () => {
  5. console.log('this is:', this);
  6. }
  7. render() {
  8. return (
  9. <button onClick={this.handleClick}>
  10. Click me
  11. </button>
  12. );
  13. }
  14. }

如果你没有使用 class fields 语法,你可以在回调中使用箭头函数

  1. class LoggingButton extends React.Component {
  2. handleClick() {
  3. console.log('this is:', this);
  4. }
  5. render() {
  6. // 此语法确保 `handleClick` 内的 `this` 已被绑定。 return ( <button onClick={() => this.handleClick()}> Click me
  7. </button>
  8. );
  9. }
  10. }

此语法问题在于每次渲染 LoggingButton 时都会创建不同的回调函数。在大多数情况下,这没什么问题,但如果该回调函数作为 prop 传入子组件时,这些组件可能会进行额外的重新渲染。我们通常建议在构造器中绑定或使用 class fields 语法来避免这类性能问题。

向事件处理程序传递参数

在循环中,通常我们会为事件处理函数传递额外的参数。例如,若 id 是你要删除那一行的 ID,以下两种方式都可以向事件处理函数传递参数:

  1. <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
  2. <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

上述两种方式是等价的,分别通过箭头函数Function.prototype.bind 来实现。

条件渲染

在react中,可以创建不同的组件来封装各种行为,然后依据应用的不同状态,只渲染对应状态下的部分内容

  1. function UserGreeting(props) {
  2. return <h1>Welcome back!</h1>;
  3. }
  4. function GuestGreeting(props) {
  5. return <h1>Please sign up.</h1>;
  6. }

再创建一个Greeting组件,它会根据用户是否登录来决定显示上面的哪一个组件

  1. function Greeting(props) {
  2. const isLoggedIn = props.isLoggedIn;
  3. if (isLoggedIn) {
  4. return <UserGreeting />;
  5. }
  6. return <GuestGreeting />;
  7. }
  8. ReactDOM.render(
  9. // Try changing to isLoggedIn={true}:
  10. <Greeting isLoggedIn={false} />,
  11. document.getElementById('root')
  12. );

元素变量

可以使用变量来存储元素。它可以有条件地渲染组件的一部分,而其他的渲染部分不会因此改变

  1. // 登录组件
  2. function LoginButton(props) {
  3. return (
  4. <button onClick={props.onClick}>
  5. Login
  6. </button>
  7. );
  8. }
  9. // 注销组件
  10. function LogoutButton(props) {
  11. return (
  12. <button onClick={props.onClick}>
  13. Logout
  14. </button>
  15. );
  16. }

下面通过创建一个LoginControl的有状态组件来根据当前状态渲染组件,同时渲染上一个实例的<Greeting />

  1. class LoginControl extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.handleLoginClick = this.handleLoginClick.bind(this);
  5. this.handleLogoutClick = this.handleLogoutClick.bind(this);
  6. this.state = {isLoggedIn: false};
  7. }
  8. handleLoginClick() {
  9. this.setState({isLoggedIn: true});
  10. }
  11. handleLogoutClick() {
  12. this.setState({isLoggedIn: false});
  13. }
  14. render() {
  15. const isLoggedIn = this.state.isLoggedIn;
  16. let button;
  17. if (isLoggedIn) {
  18. button = <LogoutButton onClick={this.handleLogoutClick} />;
  19. } else {
  20. button = <LoginButton onClick={this.handleLoginClick} />;
  21. }
  22. return (
  23. <div>
  24. <Greeting isLoggedIn={isLoggedIn} />
  25. {button}
  26. </div>
  27. );
  28. }
  29. }
  30. ReactDOM.render(
  31. <LoginControl />,
  32. document.getElementById('root')
  33. );

与运算符&&

  1. function Mailbox(props) {
  2. const unreadMessages = props.unreadMessages;
  3. return (
  4. <div>
  5. <h1>Hello!</h1>
  6. {unreadMessages.length > 0 &&
  7. <h2>
  8. You have {unreadMessages.length} unread messages.
  9. </h2>
  10. }
  11. </div>
  12. );
  13. }
  14. const messages = ['React', 'Re: React', 'Re:Re: React'];
  15. ReactDOM.render(
  16. <Mailbox unreadMessages={messages} />,
  17. document.getElementById('root')
  18. );

三目运算符

  1. render() {
  2. const isLoggedIn = this.state.isLoggedIn;
  3. return (
  4. <div>
  5. The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
  6. </div>
  7. );
  8. }
  1. render() {
  2. const isLoggedIn = this.state.isLoggedIn;
  3. return (
  4. <div>
  5. {isLoggedIn
  6. ? <LogoutButton onClick={this.handleLogoutClick} />
  7. : <LoginButton onClick={this.handleLoginClick} />
  8. }
  9. </div>
  10. );
  11. }

阻止组件渲染

如果warn的值是false,那么组件则不会渲染

  1. function WarningBanner(props) {
  2. if (!props.warn) {
  3. return null;
  4. }
  5. return (
  6. <div className="warning">
  7. Warning!
  8. </div>
  9. );
  10. }
  11. class Page extends React.Component {
  12. constructor(props) {
  13. super(props);
  14. this.state = {showWarning: true};
  15. this.handleToggleClick = this.handleToggleClick.bind(this);
  16. }
  17. handleToggleClick() {
  18. this.setState(state => ({
  19. showWarning: !state.showWarning
  20. }));
  21. }
  22. render() {
  23. return (
  24. <div>
  25. <WarningBanner warn={this.state.showWarning} />
  26. <button onClick={this.handleToggleClick}>
  27. {this.state.showWarning ? 'Hide' : 'Show'}
  28. </button>
  29. </div>
  30. );
  31. }
  32. }
  33. ReactDOM.render(
  34. <Page />,
  35. document.getElementById('root')
  36. );

列表& key

通过map()函数让数组中的每一项变双倍,然后就得到了一个新的列表doubled

  1. const numbers = [1, 2, 3, 4, 5];
  2. const doubled = numbers.map((number) => number * 2);
  3. console.log(doubled);

在react中,把数组转化为元素列表的过程是相似的

渲染多个组件

可以通过使用{}在JSX内构件一个元素集合

  1. const numbers = [1, 2, 3, 4, 5];
  2. const listItems = numbers.map((number) =>
  3. <li>{number}</li>
  4. );

我们把整个listItems插入到<ul>元素中,然后渲染进DOM

  1. ReactDOM.render(
  2. <ul>{listItems}</ul>,
  3. document.getElementById('root')
  4. );

基础列表组件

我们可以把前面的例子重构成一个组件,这个组件接收numbers数组作为参数并输出一个元素列表

  1. function NumberList(props) {
  2. const numbers = props.numbers;
  3. const listItems = numbers.map((number) =>
  4. <li>{number}</li>
  5. );
  6. return (
  7. <ul>{listItems}</ul>
  8. );
  9. }
  10. const numbers = [1, 2, 3, 4, 5];
  11. ReactDOM.render(
  12. <NumberList numbers={numbers} />,
  13. document.getElementById('root')
  14. );

当我们运行这段代码,将会看到一个警告 a key should be provided for list items,意思是当你创建一个元素时,必须包括一个特殊的 key 属性。

通过为每个列表元素分配一个key属性来解决警告

  1. function NumberList(props) {
  2. const numbers = props.numbers;
  3. const listItems = numbers.map((number) =>
  4. <li key={number.toString()}>
  5. {number}
  6. </li>
  7. );
  8. return (
  9. <ul>{listItems}</ul>
  10. );
  11. }
  12. const numbers = [1, 2, 3, 4, 5];
  13. ReactDOM.render(
  14. <NumberList numbers={numbers} />,
  15. document.getElementById('root')
  16. );

key

key帮助react识别哪些元素修改了,比如被添加或删除。因此应该给数组中每一个元素赋予一个确定的标识

  1. const numbers = [1, 2, 3, 4, 5];
  2. const listItems = numbers.map((number) =>
  3. <li key={number.toString()}>
  4. {number}
  5. </li>
  6. );

一个元素的key最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用数据中的id来作为元素的key

  1. const todoItems = todos.map((todo) =>
  2. <li key={todo.id}>
  3. {todo.text}
  4. </li>
  5. );

当元素没有确定id时,万不得已可以使用元素索引index作为key

  1. const todoItems = todos.map((todo, index) =>
  2. // Only do this if items have no stable IDs
  3. <li key={index}>
  4. {todo.text}
  5. </li>
  6. );

使用key提取组件

元素的key只有放在就近的数组上下文中才有意义
比如提取出一个ListItem组件,应该吧key保留在数组中的这个<ListItem />元素上,而不是放在ListItem组件的<li>元素上

  • 不正确的key使用方法 ```jsx function ListItem(props) { const value = props.value; return ( // 错误!你不需要在这里指定 key:
    1. {value}
  • ); }

function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) => // 错误!元素的 key 应该在这里指定: ); return (

    {listItems}
); }

const numbers = [1, 2, 3, 4, 5]; ReactDOM.render( , document.getElementById(‘root’) );

  1. - 正确的key使用方法
  2. ```jsx
  3. function ListItem(props) {
  4. // 正确!这里不需要指定 key:
  5. return <li>{props.value}</li>;
  6. }
  7. function NumberList(props) {
  8. const numbers = props.numbers;
  9. const listItems = numbers.map((number) =>
  10. // 正确!key 应该在数组的上下文中被指定
  11. <ListItem key={number.toString()} value={number} />
  12. );
  13. return (
  14. <ul>
  15. {listItems}
  16. </ul>
  17. );
  18. }
  19. const numbers = [1, 2, 3, 4, 5];
  20. ReactDOM.render(
  21. <NumberList numbers={numbers} />,
  22. document.getElementById('root')
  23. );

一个好的经验法则:在map()方法中的元素需要设置key属性

key只是在兄弟节点之间必须唯一

  1. function Blog(props) {
  2. const sidebar = (
  3. <ul>
  4. {props.posts.map((post) =>
  5. <li key={post.id}>
  6. {post.title}
  7. </li>
  8. )}
  9. </ul>
  10. );
  11. const content = props.posts.map((post) =>
  12. <div key={post.id}>
  13. <h3>{post.title}</h3>
  14. <p>{post.content}</p>
  15. </div>
  16. );
  17. return (
  18. <div>
  19. {sidebar}
  20. <hr />
  21. {content}
  22. </div>
  23. );
  24. }
  25. const posts = [
  26. {id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
  27. {id: 2, title: 'Installation', content: 'You can install React from npm.'}
  28. ];
  29. ReactDOM.render(
  30. <Blog posts={posts} />,
  31. document.getElementById('root')
  32. );

key会传递消息给react,但不会传递给组件。如果组件中需要使用到key的值,需要用其他属性显式传递

  1. const content = posts.map((post) =>
  2. <Post
  3. key={post.id}
  4. id={post.id}
  5. title={post.title} />
  6. );
  7. // Post组件可以读出props.id,但不能读出props.key

在jsx中嵌入map()

  1. function NumberList(props) {
  2. const numbers = props.numbers;
  3. const listItems = numbers.map((number) =>
  4. <ListItem key={number.toString()}
  5. value={number} />
  6. );
  7. return (
  8. <ul>
  9. {listItems}
  10. </ul>
  11. );
  12. }

JSX允许在大括号中嵌入任何表达式,可以内联map()返回结果

  1. function NumberList(props) {
  2. const numbers = props.numbers;
  3. return (
  4. <ul>
  5. {numbers.map((number) =>
  6. <ListItem key={number.toString()}
  7. value={number} />
  8. )}
  9. </ul>
  10. );
  11. }

表单

状态提升

组合& 继承