从现在开始学习React入门-React的基础知识
表格目录
今から始めるReact入門 〜 React の基本 ←★ここ
今から始めるReact入門 〜 React Router 編
今から始めるReact入門 〜 flux編
今から始めるReact入門 〜 Redux 編: immutability とは
今から始めるReact入門 〜 Redux 編: Redux 単体で状態管理をしっかり理解する
今から始めるReact入門 〜 Redux 編: Redux アプリケーションを作成する
今から始めるReact入門 〜 Mobx 編
在开始使用React之前
作为一个日常接触后端的人,我想将个人React学习的记录保留下来,以便接触前端知识。虽然已经有很多关于React的文章流传,但我想在这里主要讨论最近的React,以及React Router、Redux、其他Redux中间件和MobX。此外,我还想结合webpack v4和babel,以便在React的工作场所中可以应用到。
这次学习React主要参考的是以下React JS教程视频。
-
- React JS Tutorials
在这个过程中,有些部分因为Webpack版本过旧而无法运行,但在这里我们会对它们进行修正以适应。由于内容比较长,我想分成多个部分来进行解释。
本课所使用的文件
本次讲座所使用的文件可在以下存储库中找到。
- https://github.com/TsutomuNakamura/my-react-js-tutorials/tree/master/1-basic-react/00_start_point/react-tutorial
React 是什么?
总的来说,View层是JavaScript前端框架,具有以下特点。
宣言的 de) – 聲明的 de) – 声明的
通过在应用程序中对每个状态进行简单的设计,React 可以在数据发生更改时,仅高效更新和渲染适当的组件。
开发者无需关注找到应该更新的合适组件的逻辑。
声明式视图增加了可预测性,并且使代码更易于调试。
此外,可以使用 JSX 语法(一种在 JavaScript 内嵌入 HTML 标签的语法),使渲染的形式更加直观。
组件化
通过构建管理自身状态的封装组件,可以通过调用这些组件来创建复杂的UI。这些组件不是模板,而是使用JavaScript编写,可以轻松传递丰富的数据到应用程序,并且可以在DOM之外维持状态。
循环使用
由于React不对开发者的其他技术知识作出假设,因此可以在不重新编写现有代码的情况下,使用React开发新功能。
例如,可以使用Node来支持SSR(服务器端渲染),也可以使用React Native开发强大的移动应用程序。
此外,React 有一个特点是将Facebook作为其后台,之前可能会因为其采用BSD + 特许许可证等许可形式而使某些人对企业应用程序的开发产生犹豫,但在2017年9月左右改为了MIT许可证,使其比以前更易于使用。
既然我们已经掌握了React的基本特点,那么接下来就立即开始使用React来进行编程吧。
环境准备
这次我们是在以下这样的环境中创建的。
-
- 環境概要
演算子
意味
node version
v8 系
npm version
5 系
webpack
4 系
OS
Arch Linux
让我们以一个简单的结构作为例子来体验一下React,以便确认React的基本操作。
创建工作空间
创建一个名为react-tutorial的工作目录,以便于制作一个能够体验React基本操作的应用程序。
$ mkdir react-tutorial
$ cd react-tutorial
$ mkdir -p src/js
使用npm init命令来创建项目。
$ npm init
......
package name: (react-tutorial)
version: (1.0.0)
description:
entry point: (index.js) webpack.config.js # <- "webpack.config.js" 入力(先にwebpack.config.js 作っておけばデフォルトで選択される)
test command:
git repository:
keywords:
author: Your Name
license: (ISC)
......
補充:根據 @ksilverwall 用戶的評論,如果在創建項目時沒有輸入description和git repository,當執行後續的npm install等命令時會出現以下警告。
npm WARN react-tutorial@1.0.0 No description
npm WARN react-tutorial@1.0.0 No repository field.
这个警告本身没有问题,所以可以按原样进行,没关系。但是,如果有人在意的话,请在描述和Git仓库中填入适当的值。
接下来,我们将安装React、Webpack和Babel。
在实际项目中,我们将使用Babel来支持ES6语法,并使用Webpack进行模块打包和开发。
$ npm install --save-dev webpack webpack-cli webpack-dev-server
$ npm install -g webpack webpack-cli
$ npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader
$ npm install --save-dev react react-dom
创建webpack.config.js文件并编写捆绑规则。
通过以下方式设置webpack.config.js,从./src/js/client.js作为起点读取文件内部的import语法,并将这些源代码进行模块捆绑。
var debug = process.env.NODE_ENV !== "production";
var webpack = require('webpack');
var path = require('path');
module.exports = {
context: path.join(__dirname, "src"),
entry: "./js/client.js",
module: {
rules: [{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
use: [{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-react', '@babel/preset-env']
}
}]
}]
},
output: {
path: __dirname + "/src/",
filename: "client.min.js"
},
plugins: debug ? [] : [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({ mangle: false, sourcemap: false }),
]
};
接下来,创建src/index.html文件。
在src/index.html文件中,指定加载由Webpack创建的client.min.js文件。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>React Tutorials</title>
<!-- change this up! http://www.bootstrapcdn.com/bootswatch/ -->
<link href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.6/cosmo/bootstrap.min.css" type="text/css" rel="stylesheet"/>
</head>
<body>
<div id="app"></div>
<script src="client.min.js"></script>
</body>
</html>
让我们打开client.js文件并使用React的JSX在屏幕上呈现”Welcome!”。
import React from "react";
import ReactDOM from "react-dom";
class Layout extends React.Component {
render() {
return (
<h1>Welcome!</h1>
);
}
}
const app = document.getElementById('app');
ReactDOM.render(<Layout/>, app);
用webpack命令来创建client.min.js文件,然后在Chrome中打开index.html文件即可,准备工作已完成。
$ webpack --mode development
Hash: f97a4ff0cc28741ce49d
Version: webpack 4.6.0
Time: 995ms
Built at: 2018-04-29 11:18:20
Asset Size Chunks Chunk Names
client.min.js 1.66 MiB main [emitted] main
Entrypoint main = client.min.js
[./js/client.js] 2.31 KiB {main} [built]
+ 21 hidden modules
$ google-chrome-stable ./src/index.html

欢迎!看到显示了。使用JSX进行首次元素渲染。
尝试通过更改client.js的内容来确认显示是否会发生变化。
import React from "react";
import ReactDOM from "react-dom";
class Layout extends React.Component {
render() {
return (
- <h1>Welcome!</h1>
+ <h1>It works!</h1>
);
}
}
const app = document.getElementById('app');
ReactDOM.render(<Layout/>, app);
购买一个全新的,则使用webpack命令进行转译,然后再次在Chrome中打开屏幕进行尝试。
$ webpack --mode development
......
$ google-chrome-stable ./src/index.html

这次显示为 “It works!”。
React 使用JSX语法可以渲染屏幕。
使用webpack-dev-server启动开发用的web服务器。
webpack提供了一个用于开发的web服务器。
通过使用开发用的web服务器(webpack-dev-server),您可以同时进行捆绑和开发中服务的发布,从而大大提高开发效率,这是一个不容错过的功能。
那么让我们来试着启动webpack-dev-server吧。
$ ./node_modules/.bin/webpack-dev-server --content-base src --mode development
如果使用webpack 4版本的话
$ webpack serve
请以另一种方式执行。
您可以尝试在Web浏览器中访问http://localhost:8080以查看当前状态。然后应该会显示先前显示的It works!。

让我们在这个状态下,修改并覆盖保存./src/js/client.js。
import React from "react";
import ReactDOM from "react-dom";
class Layout extends React.Component {
render() {
return (
- <h1>It works!</h1>
+ <h1>Welcome!</h1>
);
}
}
const app = document.getElementById('app');
ReactDOM.render(<Layout/>, app);

使用webpack-dev-server可以有效地进行开发,这样您可以在Web页面上实时查看到变化。
在npm脚本中注册webpack-dev-server的启动命令。
将webpack-dev-server命令注册为npm脚本,添加到package.json中,并配置让它通过npm start命令来启动。在npm脚本中,由于会自动将./node_modules目录添加到PATH中,所以只需要在package.json中如下配置即可:
......
"scripts": {
+ "start": "webpack-dev-server --content-base src --mode development --inline",
"test": "echo \"Error: no test specified\" && exit 1"
},
......
当附加内容编辑完成后,尝试按照以下方式启动webpack-dev-server。
$ npm start
我认为如果在这种状态下,像之前一样通过Web浏览器访问http://localhost:8080,就可以看到由React渲染的页面。
我们已经准备好了开发环境。接下来我们将开始开发一个基于实际React开发场景的Web应用程序。
JSX可以用中文翻译为“JavaScript XML”。
我用webpack和babel创建了一个简单的React应用项目。
接下来我将解释一下在React应用程序的程序中出现的JSX。
关于JSX
创建React应用程序时,出现了以下描述。
......
render() {
return (
<h1>It works!</h1>
);
}
......
这个
…
的写法是HTML标签,在JavaScript的语法中并不常见。
然而,通过这种写法,实际上将HTML标签的内容渲染到了屏幕上。
这是在执行webpack命令时,内部会调用babel并将其转换为一种常见的Web浏览器可解释的JavaScript语法。
......
return React.createElement(
"h1",
null,
"Welcome!"
);
......
调用React.createElement方法,并将h1作为HTML标签名,属性值为null,被标签包裹的文本Welcome!作为参数传递。
实际上,当单独运行babel时,它会被编译成稍微复杂一些的形式。
$ npm install -g --no-save @babel/cli
$ npm install -g --no-save @babel/core @babel/preset-react @babel/preset-env
$ babel --presets @babel/preset-react,@babel/preset-env ./src/js/client.js
......
_createClass(Layout, [{
key: "render",
value: function render() {
return _react2.default.createElement(
"h1",
null,
"It works!"
);
}
}]);
......
然而,无论如何,它将被转换为符合JavaScript语法的语法。
通过使用webpack和babel,React/JSX语法会被编译为典型的JavaScript,以便在任何Web浏览器上都可以执行。
在描述多个组件时需要注意的要点
当使用JSX时,您可以在JavaScript中直接嵌入标签,就像正常编写HTML一样。不过,需要注意一些要点。现在让我们将src/js/client.js按照以下方式进行修改。
import React from "react";
import ReactDOM from "react-dom";
class Layout extends React.Component {
render() {
return (
<h1>Welcome!</h1>
+ <h1>It's works!</h1>
);
}
}
const app = document.getElementById('app');
ReactDOM.render(<Layout/>, app);
按下Google Chrome的F12键打开控制台,您可能会在错误消息中看到以下类似的信息。

SyntaxError: Adjacent JSX elements must be wrapped in an enclosing tag
只能将JSX组件排成两行,必须通过父级组件进行包裹才能完成。
通过以下方式进行描述,可以正确渲染错误。
import React from "react";
import ReactDOM from "react-dom";
class Layout extends React.Component {
render() {
return (
- <h1>Welcome!</h1>
- <h1>It's works!</h1>
+ <div>
+ <h1>Welcome!</h1>
+ <h1>It's works!</h1>
+ </div>
);
}
}
const app = document.getElementById('app');
ReactDOM.render(<Layout/>, app);
关于变量的处理
在JSX中嵌入用JavaScript定义的变量,可以使用{变量名}进行嵌入。
import React from "react";
import ReactDOM from "react-dom";
class Layout extends React.Component {
render() {
let name = "Tsutomu";
return (
- <div>
- <h1>Welcome!</h1>
- <h1>It's works!</h1>
- </div>
+ <h1>It's {name}!</h1>
);
}
}
const app = document.getElementById('app');
ReactDOM.render(<Layout/>, app);
还可以通过使用{数式}将数学公式的计算结果嵌入其中。
import React from "react";
import ReactDOM from "react-dom";
class Layout extends React.Component {
render() {
return (
- <h1>It's {name}!</h1>
+ <h1>It's {1 + 2}!</h1>
);
}
}
const app = document.getElementById('app');
ReactDOM.render(<Layout/>, app);
另外,您也可以直接将函数嵌入替代变量的用法。
import React from "react";
import ReactDOM from "react-dom";
class Layout extends React.Component {
render() {
return (
- <h1>It's {1 + 2}!</h1>
+ <h1>It's {this.get_result(3)}!</h1>
);
}
+ get_result(num) {
+ return 1 + num;
+ }
}
const app = document.getElementById('app');
ReactDOM.render(<Layout/>, app);
此外,您可以创建匿名函数并立即调用它。
import React from "react";
import ReactDOM from "react-dom";
class Layout extends React.Component {
render() {
return (
- <h1>It's {this.get_result(3)}!</h1>
+ <h1>It's { ((num) => { return 1 + num; })(3) }!</h1>
);
}
- get_result(num) {
- return 1 + num;
- }
}
const app = document.getElementById('app');
ReactDOM.render(<Layout/>, app);
此外,还可以使用构造函数来引用在其中初始化的成员变量。
import React from "react";
import ReactDOM from "react-dom";
class Layout extends React.Component {
+ constructor() {
+ super();
+ this.name = "Tsutomu";
+ }
render() {
return (
- <h1>It's { ((num) => { return 1 + num; })(3) }!</h1>
+ <h1>It's {this.name}!</h1>
);
}
}
const app = document.getElementById('app');
ReactDOM.render(<Layout/>, app);
React 组件化
通过将 React 组件化,可以将内容分散到多个文件中,而不是像上一篇文章那样把所有内容都放在一个文件中,这样可以提高再利用性。
import React from "react";
import ReactDOM from "react-dom";
class Layout extends React.Component {
constructor() {
super();
this.name = "Tsutomu";
}
render() {
return (
<h1>It's {this.name}!</h1>
);
}
}
const app = document.getElementById('app');
ReactDOM.render(<Layout/>, app);
将此源代码中的Layout类移植到新的文件src/js/components/Layout.js中。
$ mkdir -p ./src/js/components
$ touch src/js/components/Layout.js
请创建src/js/components/Layout.js文件并将以下内容从src/js/client.js移动到该文件中。
另外,我们将使用export语法,以便稍后可以从src/js/client.js进行引用并从外部访问。
import React from "react";
export default class Layout extends React.Component {
constructor() {
super();
this.name = "Tsutomu";
}
render() {
return (
<h1>It's {this.name}!</h1>
);
}
}
我们将在 client.js 中导入这个 Layout 组件。
import React from "react";
import ReactDOM from "react-dom";
+import Layout from "./components/Layout";
-class Layout extends React.Component {
- constructor() {
- super();
- this.name = "Tsutomu";
- }
- render() {
- return (
- <h1>It's {this.name}!</h1>
- );
- }
-}
-
const app = document.getElementById('app');
ReactDOM.render(<Layout/>, app);
通过这种方式,JSX的Layout标签现在可以像以前一样在client.js中使用。
执行npm start命令并在http://localhost:8080上确认之前的It’s Tsutomu!仍然显示。
创建 Header、Footer 组件
创建了Layout组件之后,接下来我们要创建Header和Footer组件。
创建Header组件
请创建src/js/components/Header.js文件,并开始制作Header组件。
import React from "react";
export default class Header extends React.Component {
render() {
return (
<header>header</header>
);
}
}
一旦创建了Header组件,就可以将其引入到Layout.js中。
import React from "react";
+import Header from "./Header";
export default class Layout extends React.Component {
- constructor() {
- super();
- this.name = "Tsutomu";
- }
render() {
return (
- <h1>It's {this.name}!</h1>
+ <div>
+ <Header />
+ </div>
);
}
}

请问header是否正常显示?
现在我们尝试将Layout.js内的Header组件增加到3个,以确保可重用性。
import React from "react";
import Header from "./Header";
export default class Layout extends React.Component {
render() {
return (
<div>
<Header />
+ <Header />
+ <Header />
</div>
);
}
}

页脚组件
接下来我们将创建 Footer 组件。
import React from "react";
export default class Footer extends React.Component {
render() {
return (
<footer>footer</footer>
);
}
}
我们将这个内容像之前一样引入到Layout.js中。
import React from "react";
import Header from "./Header";
+import Footer from "./Footer";
export default class Layout extends React.Component {
render() {
return (
<div>
<Header />
- <Header />
- <Header />
+ <Footer />
</div>
);
}
}

补充:关于将多个组件排列在一起的注意事项
如果需要将多个组件并列排列,也可以创建一个数组并使用它。
import React from "react";
import Header from "./Header";
import Footer from "./Footer";
export default class Layout extends React.Component {
render() {
let components = [<Header />, <Footer />];
return (
<div>
{components}
</div>
);
}
}
调用组件中的组件。
我刚刚创建了Header组件,但是这个组件也可以调用其他组件。
通常情况下,如果要从一个组件中调用另一个组件,通常会创建一个用于存放其他组件的目录。
为了在header区域使用h1元素来显示标题,我们将创建一个Title组件。首先,创建src/js/components/Header目录,在其中创建一个Title.js文件。
$ mkdir -p src/js/components/Header
import React from "react";
export default class Title extends React.Component {
render() {
return (
<h1>Welcome!</h1>
);
}
}
创建组件后,尝试从Header组件中引用Title组件。
import React from "react";
+import Title from "./Header/Title";
export default class Header extends React.Component {
render() {
return (
- <header>header</header>
+ <header>
+ <Title />
+ </header>
);
}
}
让我们打开Web浏览器并确认显示。标题应该显示在标题中。
以上是关于组件的说明。
通过将布局的各个部分组件化,可以增加重复使用性,并期望提高开发效率和设计统一性。
通过巧妙地创建可重复使用的组件,我们可以高效地开发大型Web项目的应用程序。
React的state和生命周期
React 有一个叫做state的状态数据。这个state是用来保存应用程序的状态的,它存放了关于如何渲染组件的信息。state可以通过setState方法进行修改,当state发生变化时,会自动触发重新渲染组件的命令,并将其排队。此外,setState方法是一种用于修改state状态并重新渲染组件的基本方法,在React中经常被使用。
让我们在这里学习React和state的特点,并学习如何创建具有响应性的应用程序。
关于国家
在React组件中,state位于拥有React.Component类作为父类的类中,可以通过this.state进行访问。
那么,让我们实际组装一下。
请按照以下方式定义构造函数并设置this.state的初始值,使用setTimeout函数使得在初始界面显示后1000毫秒后更新屏幕显示的程序。
import React from "react";
import Header from "./Header";
import Footer from "./Footer";
export default class Layout extends React.Component {
+ constructor() {
+ super();
+ this.state = {name: "Tsutomu"};
+ }
render() {
+ setTimeout(
+ () => { this.setState({name: "Hello"}); }
+ , 1000
+ );
return (
<div>
+ {this.state.name}
<Header />
<Footer />
</div>
);
}
}
当这个this.state的数据通过setState方法设置或修改后,会自动检测更新差异,并且只重新呈现JSX内部必要的地方,使得dom重新渲染。

为了使其更加直观易懂,您可以通过按下F12键打开Chrome开发者模式并选择Rendering,然后勾选Paint flashing来动态转换dom,并确认屏幕变化。

如果这样做,可以实时显示状态变化的DOM,并以不同的颜色进行标示。
通过观察这种显示方式,可以了解到React在重新渲染时不会更新整个组件,而是只更新需要更新的部分。
如果查看相关的源代码位置…
......
return (
<div>
{this.state.name}
<Header />
<Footer />
</div>
);
......
这段文本以及前面的显示已经确认,虽然有一些文字不是来自于`this.state.name`,但是它们一起更新的只是`Header`和`Footer`组件。React 在前端 JavaScript 中,即使涉及成本高的 DOM 渲染,也只会更新必要的部分,因此无需编写复杂的处理逻辑,就可以实现高效的渲染处理。
关于道具
HTML 标签中的属性可以通过指定参数来对标签元素进行设置,从而在相同的元素中实现细微的差异,例如改变大小、改变颜色或注册事件等等。
在 React 的 JSX 中,也可以通过传递参数来使用每个组件,并且通过这样做可以为每个组件传递单独的值作为参数。
在 React 的 JSX 中,我们称之为 Props。
那么,让我们立刻使用 Props 进行编程吧。
import React from "react";
import Header from "./Header";
import Footer from "./Footer";
export default class Layout extends React.Component {
- constructor() {
- super();
- this.state = {name: "Tsutomu"};
- }
render() {
- setTimeout(
- () => { this.setState({name: "Nakamura"}); }
- , 1000);
+ const title = "Welcome Tsutomu!";
return (
<div>
- {this.state.name}
- <Header />
+ <Header title={title} />
<Footer />
</div>
);
}
}
在上述的文件中,
中的title={title} 是一个props。
接下来打开Header.js文件。
在Header.js中,您可以通过this.props访问从Layout.js传递过来的props。
import React from "react";
import Title from "./Header/Title";
export default class Header extends React.Component {
render() {
+ console.log(this.props);
return (
<header>
<Title />
</header>
);
}
}
当检查Web浏览器的开发者窗口时,this.props 的显示如下。

要传递一个字符串,可以使用{“string”}的形式来传递。
import React from "react";
import Header from "./Header";
import Footer from "./Footer";
export default class Layout extends React.Component {
render() {
const title = "Welcome Tsutomu!";
return (
<div>
- <Header title={title} />
+ <Header name={"some string"} title={title} />
<Footer />
</div>
);
}
}

另外,如果创建了两个Header组件并传递不同的props,那么将调用具有不同props的每个Header组件。
import React from "react";
import Header from "./Header";
import Footer from "./Footer";
export default class Layout extends React.Component {
render() {
const title = "Welcome Tsutomu!";
return (
<div>
- <Header name={"some string"} title={title} />
+ <Header title={title} />
+ <Header title={"Thank you"} />
<Footer />
</div>
);
}
}
我们已经理解了Props的外部要求,下一步是从Header组件传递props到Title组件。
import React from "react";
import Title from "./Header/Title";
export default class Header extends React.Component {
render() {
- console.log(this.props);
return (
<header>
- <Title />
+ <Title title={this.props.title} />
<header>
);
}
}
在组件中,我们可以这样写,并使用title props将传递的值在
标签中显示出来。
import React from "react";
export default class Title extends React.Component {
render() {
return (
- <h1>Welcome!</h1>
+ <h1>{this.props.title}</h1>
);
}
}
保存并在Web浏览器上通过http://localhost:8080进行屏幕确认。

会显示两个不同标题的组件。
通过使用props,可以大大提高一个组件的可重用性。
state 和 props 的组合
我们也可以将state和props组合在一起使用。
让我们将Layout.js的代码修改如下。
import React from "react";
import Header from "./Header";
import Footer from "./Footer";
export default class Layout extends React.Component {
+ constructor() {
+ super();
+ this.state = {title: "Welcome"};
+ }
render() {
- const title = "Welcome Tsutomu!";
+ setTimeout(
+ () => { this.setState({title: "Welcome Tsutomu!"}); },
+ 2000
+ );
return (
<div>
- <Header title={title} />
+ <Header title={this.state.title} />
<Header title={"Thank you"} />
<Footer />
</div>
);
}
}
通过将props应用于state的值,可以实现只有第一个Header组件在显示后2秒更改标题。
关于活动和数据变更
打开Header.js文件,添加一个输入框,通过用户在表单中输入的数据实时触发事件。
import React from "react";
import Title from "./Header/Title";
export default class Header extends React.Component {
render() {
return (
<header>
<Title title={this.props.title} />
+ <input />
</header>
);
}
}
在之前的编辑中,Layout.js中有两个Header组件的记录,所以我们需要删除一个。
import React from "react";
import Header from "./Header";
import Footer from "./Footer";
export default class Layout extends React.Component {
constructor() {
super();
this.state = {title: "Welcome"};
}
render() {
setTimeout(
() => { console.log("called"); this.setState({title: "Welcome Tsutomu!"}); },
2000
);
return (
<div>
<Header title={this.state.title} />
- <Header title={"Thank you"} />
<Footer />
</div>
);
}
}
让我们来确认一下 http://localhost:8080 的情况。
然后,页面会出现如下的情况,Title 中会添加一个 input。

然而,如果保持当前状态,即使在表单中输入文字也不会触发任何事件。
接下来,让我们添加一个处理程序,以获取在此输入表单中输入的值,并实时渲染标题。
添加用于获取输入内容的处理程序
让我们在Layout.js中创建一个changeTitle方法,并将它传递给Header组件。
import React from "react";
import Header from "./Header";
import Footer from "./Footer";
export default class Layout extends React.Component {
constructor() {
super();
this.state = {title: "Welcome"};
}
+ changeTitle(title) {
+ this.setState({title});
+ }
render() {
- setTimeout(
- () => { console.log("called"); this.setState({title: "Welcome Tsutomu!"}); },
- 2000
- );
return (
<div>
- <Header title={this.state.title} />
+ <Header changeTitle={this.changeTitle.bind(this)} title={this.state.title} />
<Footer />
</div>
);
}
}
上述的changeTitle函数的this.setState({title}); 这种写法是ES6的写法,与this.setState({title: title}); 有相同的意思。
此外,通过将方法通过props传递给Header组件作为
通过以下方式,Header组件和Title组件只需要直接显示Layout组件传递的值,而无需管理Layout组件何时传递什么值。
import React from "react";
import Title from "./Header/Title";
export default class Header extends React.Component {
+ handleChange(e) {
+ const title = e.target.value;
+ this.props.changeTitle(title);
+ }
render() {
console.log(this.props);
return (
<header>
<Title title={this.props.title} />
- <input />
+ <input value={this.props.title} onChange={this.handleChange.bind(this)} />
</header>
);
}
}
在这个状态下,打开http://localhost:8080 并尝试在输入框中输入文本。
输入框中输入的值将实时反映在标题上,并显示在屏幕上。

在这里,我们学习了使用React进行基本状态管理和渲染。当React的状态发生改变时,状态会立即重新渲染,你有没有对此有所了解呢?目前,你已经可以无问题地使用React创建简单的应用程序了。
接下来我们将学习使用React Router 实现内容列表显示和通过不同的路径在SPA中实现网页的方法。
附注:关于Layout组件中的bind(this)这一描述
在将方法从Layout组件传递给Header组件时,我们使用了
changeTitle(title) {
this.setState({title});
}
在上述的代码中,this.setState({title}); 中的this 不再是Layout 实例。
因此,setState函数也不再是Layout类内的函数,可能会产生意想不到的行为。
为了确保能够确切调用Layout实例的setState函数,我们需要将bind函数的参数this(Layout实例)与
補充:可以通过public class fields的语法来省略bind的描述。
通过使用公共类字段语法,可以省略对绑定的声明。
...
changeTitle = (title) => { /* <- 関数の宣言をこのように変える */
this.setState({title});
}
render() {
return (
<div>
<Header changeTitle={this.changeTitle} title={this.state.title} /> /* <- bind の記載が省略できる */
<Footer />
</div>
);
}
- 2019-04-30 @6in さんのコメントより追記:
需要安装@babel/plugin-proposal-class-properties插件,并将其作为.babelrc或webpack.config.js中的插件指定,以使用public class fields语法。
$ npm install --save-dev @babel/plugin-proposal-class-properties
{
"plugins": [
["@babel/plugin-proposal-class-properties", { "loose": true }]
]
}
......
use: [{
loader: 'babel-loader',
options: {
- presets: ['@babel/preset-react', '@babel/preset-env']
+ presets: ['@babel/preset-react', '@babel/preset-env'],
+ plugins: [
+ ['@babel/plugin-proposal-class-properties', { 'loose': true }]
+ ]
}
......
请在完成之后重新运行npm start。
補充:使用箭头函数可以省略bind的声明。
使用箭头函数也可以省略bind的声明。
...
changeTitle(title) {
this.setState({title});
}
render() {
return (
<div>
<Header changeTitle={(e) => this.handleClick(e)} title={this.state.title} />
<Footer />
</div>
);
}
这种写法的缺点通常不会成为问题,但有一些注意点。
使用这种方法时,每次调用render方法都会生成changeTitle函数。
而且,如果子组件通过prop并且以这种方式传递函数,则子组件将始终重新渲染,除非单独编写shouldComponentUpdate()方法。
由于这些问题,通常建议使用bind或public class fields语法的方法。
请提供以下选项的中文本地化:
React A JavaScript library for building user interfaces
https://reactjs.org/
REACT JS TUTORIAL #1 – Reactjs Javascript Introduction & Workspace Setup
REACT JS TUTORIAL #2 – Reactjs Components & Rendering
REACT JS TUTORIAL #3 – Composing Multiple React.js Components
Best way to build/compile/deploy ReactJS to production
https://stackoverflow.com/questions/37152773/best-way-to-build-compile-deploy-reactjs-to-production
Handling Events
https://reactjs.org/docs/handling-events.html
Function.prototype.bind()
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
Public Class Fields saves sooo many keystrokes in React code
https://www.peterbe.com/plog/public-class-fields