React 基础语法
Posted devywb
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React 基础语法相关的知识,希望对你有一定的参考价值。
一、Hello World
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>React demo</title>
<script src="../build/react.js"></script>
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function Hello() {
return <h1>Hello world.</h1>;
}
ReactDOM.render(
<Hello/>,
document.getElementById(‘root‘)
)
</script>
</body>
</html>
二、JSX 简介
JSX 是一种 javascript 的语法扩展。推荐在 React 中使用 JSX 来描述用户界面,JSX 用来声明 React 当中的元素。
2.1 在 JSX 中使用表达式
在 JSX 当中的表达式要包含在大括号里。
const element = (
<h1>
Hello, {formatName(user)}!
</h1>
);
推荐在 JSX 代码的外面括上小括号,这样可以防止分号自动插入的 BUG。
JSX 本身其实也是一种表达式
在编译之后,JSX 其实会被转化为普通的 JavaScript 对象。
JSX 属性
const element = <img src={user.avatarUrl}></img>;
使用了大括号包裹的 JavaScript 表达式时就不要再到外面套引号了。 JSX 会将引号当中的内容识别为字符串而不是表达式。
JSX 嵌套
如果 JSX 标签是闭合式的,那么你需要在结尾处用/>,就好像 XML/HTML 一样:
const element = <img src={user.avatarUrl}/>;
JSX 标签同样可以相互嵌套:
const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
)
警告:
因为 JSX 的特性更接近 JavaScript 而不是 HTML , 所以 React DOM 使用 camelCase 小驼峰命名来定义属性的名称,而不是使用 HTML 的属性名称。
例如,class 变成了 className,而 tabindex 则对应着 tabIndex.
JSX 代表 Objects
Babel 转译器会把 JSX 转换成一个名为 React.createElement() 的方法调用。
下面两种代码的作用是完全相同的:
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
const element = React.createElement(
‘h1‘,
{className: ‘greeting‘},
‘Hello, world!‘
);
React.createElement() 这个方法首先会进行一些避免 bug 的检查,之后返回一个类似下面例子的对象:
// 注意: 以下示例是简化过的(不代表在 React 源码中是这样)
const element = {
type: ‘h1‘,
props: {
className: ‘greeting‘,
children: ‘Hello, world‘
}
};
这样的对象被称为“React 元素”。
三、元素渲染
元素是构成 React 应用的最小单位。
3.1 将元素渲染到 DOM 中
首先定义一个 id 为 root 的 div:
<div id=‘root‘></div>
在此 div 中的所有内容都将由 React DOM 来管理,所以我们将其称之为“根” DOM 节点。
我们用 React 开发应用时一般只会定义一个根节点。
要将 React 元素渲染到根 DOM 节点中,我们通过把它们都传递给 ReactDOM.render() 的方法来将其渲染到页面上:
const element = <h1>Hello,world</h1>;
ReactDOM.render(
element,
document.getElementById(‘root‘)
)
四、组件 & Props
组件可以将 UI 切分为一些独立的、可复用的部件,这样你就只需专注于构建每一个单独的部件。
组件从概念上看就像是函数,它可以接收任意的输入值(称之为“props”),并返回一个需要在页面上展示的 React 元素。
4.1 函数定义/类定义组件
定义一个组件最简单的方式是使用 JavaScript 函数:
// 函数定义组件
function Welcome(props){
return <h1>Helle,{props.name}</h1>;
}
也可以使用 ES6 class 来定义一个组件:
拓展:
ES6 是什么?
ES6:全称 ECMScript 6.0。是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布。
// 类定义组件
class Welcome extents React.Component {
render(){
return <h1>Hello,{this.props.name}</h1>;
}
}
4.2 组件渲染
第一步,定义一个 Welcome 组件:
function Welcome(props) {
return <h1>Hello,{props.name}</h1>;
}
第二步,使用该组件创建 React 元素:
const element = <Welcome name=‘kevin‘/>;
第三步,使用 ReactDOM.render() 方法将 React 元素渲染到页面上:
ReactDOM.render(
element,
document.getElementById(‘root‘);
)
4.3 组合组件
组件可以在它的输出中引用其他组件:
function Welcome(props) {
return <h1>Hello,{props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name=‘kevin‘/>
<Welcome name=‘tom‘/>
<Welcome name=‘bob‘/>
</div>
);
}
ReactDOM.render(
<App/>,
document.getElementById(‘root‘)
);
警告:
组件的返回值只能有一个根元素。
4.4 props 的只读性
props 是不可变的
五、State & 生命周期
状态与属性十分相似,但是状态是私有的,完全受控于当前组件。
使用类定义组件,就可以使用局部状态、生命周期钩子等特性。
5.1 为一个类添加局部状态
第一步:使用 ES6 class 定义一个组件
class Clock extents React.component {
render() {
return (
<div>
<h1>Hello,world!</h1>
<h2>It is {this.state.date.toLocaleTimeString}</h2>
</div>
)
}
}
第二步:添加一个类构造函数来初始化状态 this.state
class Clock extents React.component {
constructor(props) {
super(props);
this.state = {date : new Date()};
}
render() {
return (
<div>
<h1>Hello,world!</h1>
<h2>It is {this.state.date.toLocaleTimeString}</h2>
</div>
)
};
}
第三步:使用 ReactDOM.render() 方法渲染组件到页面
class Clock extents React.component {
constructor(props) {
super(props);
this.state = {date : new Date()};
}
render() {
return (
<div>
<h1>Hello,world!</h1>
<h2>It is {this.state.date.toLocaleTimeString}</h2>
</div>
)
};
}
ReactDOM.render(
<Clock/>,
document.getElementById(‘root‘)
)
5.2 将生命周期方法添加到类中
在 5.1 中,我们只是添加了一个状态,那么,如何更新状态呢?答案是:使用生命周期方法。
class Clock extents React.component {
constructor(props) {
super(props);
this.state = {date : new Date()};
}
componentDidMount() {
this.timeID = setInterval(
() => this.tick(),1000
);
}
componentWillUnmount() {
clearInterval(this.timeID);
}
tick(){
this.setState({
date : new Date()
});
}
render() {
return (
<div>
<h1>Hello,world!</h1>
<h2>It is {this.state.date.toLocaleTimeString}</h2>
</div>
)
};
}
ReactDOM.render(
<Clock/>,
document.getElementById(‘root‘)
)
当 Clock 的输出插入到 DOM 中时,React 会调用 componentDidMount() 生命周期方法。上面代码示例中,我们在该方法中设置了一个定时器,每个 1 秒钟调用一次 tick() 方法。
在 tick() 方法中,Clock 组件通过使用包含当前时间的对象调用 setState() 来更新状态。当 React 发现状态已经更新时,会再次调用 ReactDOM.render() 方法更新 DOM。
当 Clock 组件被从 DOM 中移除,React 会调用 componentWillUnmount() 生命周期方法。
5.3 正确地使用状态
- 不要直接更新状态
构造函数是唯一能够初始化 this.state 的地方。其他地方更薪状态只能使用 this.setState();
- 状态更新可能是异步的
不太懂 TODO
- 状态更新合并
不太懂 TODO
5.4 数据自顶向下流动
父组件或子组件都不能知道某个组件是有状态还是无状态,并且它们不应该关心某组件是被定义为一个函数还是一个类。
所以状态通常被成为局部或封装。除了拥有并设置它的组件外,其他组件不可访问。
但组件可以选择将其状态作为属性传递给其子组件。
这通常被称为 自顶向下 或 单向 数据流。任何状态始终由某些特定组件所有,并且该状态导出的任何数据或 UI 只能影响树中 下方 的组件。
六、事件处理
- React 事件绑定属性的命名采用驼峰式写法,而不是小写。
- 如果采用 JSX 的语法你需要传入一个函数作为事件处理函数,而不是字符串。
例如,传统的 HTML 写法:
<button onclick="activateLasers()">
Activate Lasers
</button>
React 写法:
<button onClick={activateLasers}>
Activate Lasers
</button>
- 在 React 中,不能使用返回 false 的方式阻止默认行为。你必须明确的使用 preventDefault。
6.1 开关实例
class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true};
// 绑定 this
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState(
prevState => ({
isToggleOn: !prevState.isToggleOn
})
);
}
render () {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? ‘ON‘ : ‘OFF‘}
</button>
);
}
}
ReactDOM.render(
<Toggle/>,
document.getElementById(‘root‘)
)
6.2 向事件处理程序传递参数
有两种方式向事件处理程序传递参数,分别是:
- arrow function:箭头函数
<button onClick={(e) => this.deleleRow(id,e)}>Delete Row</button>
- Function.prototype.bind:绑定
<button onClick={this.deleleRow.bind(this,id)}>Delete Row</button>
参数 e 作为 React 的事件对象将会被作为第二个参数进行传递。
箭头函数的方式,事件对象必须显式传递;
绑定的方式,事件对象以及更多的参数将会被隐式传递。值得注意的是,通过绑定的方式向监听函数传参,在类组件中定义的监听组件,事件对象 e 排在所传递参数的后面。
七、条件渲染
React 中的条件和 JavaScript 中的一致,使用 JavaScript 操作符 if 或 条件运算符 来创建表示当前状态的元素,然后让 React 来更新 UI。
7.1 if
示例:
function UserGreeting() {
return <h1>Welcome back!</h1>;
}
function GuestGreeting() {
return <h1>Please sign up.</h1>
}
function Greeting(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn){
return <UserGreeting/>
}
return <GuestGreeting/>
}
ReactDOM.render(
<Greeting isLoggedIn={true}/>,
document.getElementById(‘root‘)
)
7.2 与运算符 &&
function Mailbox(props) {
const message = props.message;
return (
<div>
<h1>Hello!</h1>
{message.length > 0 &&
<h2>
You have {message.length} unread message.
</h2>}
</div>
)
}
const message = [‘React‘, ‘Re:React‘,‘Re:Re:React‘];
ReactDOM.render(
<Mailbox message={message}/>,
document.getElementById(‘root‘)
)
true && expression 总是返回 expression,而 false && expression,React 会忽略并跳过它。
7.3 三目运算符
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {isLogin: false};
this.login = this.login.bind(this);
}
login() {
this.setState(
prevState => ({
isLogin: !prevState.isLogin
})
);
}
render (){
return (
<div>
<h1>
{this.state.isLogin ? ‘Welcome‘ : ‘Please Login‘}
</h1>
<button onClick={this.login}></button>
</div>
);
}
}
ReactDOM.render(
<Login/>,
document.getElementById(‘root‘)
)
7.4 阻止组件渲染
让组件的 render 方法返回 null 即可阻止组件渲染。
八、列表 & Keys
function ToDoList(props) {
const things = props.things;
const todolist = things.map((thing) =>
<li key={thing.toString()}>{thing}</li>
);
return (
<ul>{todolist}</ul>
)
}
const things = [1,2,3,4,5];
ReactDOM.render(
<ToDoList things={things}/>,
document.getElementById(‘root‘)
)
- 使用 map() 函数遍历数组
- 应当给数组中的每一个元素赋予一个确定的标识(key)。这样,当某些元素被增加或删除时能帮助 React 识别哪些元素发生了变化。
- 元素的 key 只有在它和它的兄弟节点对比时才有意义。
- 元素的 key 在其兄弟元素之间应该唯一。
九、表单
9.1 受控组件
在HTML当中,像
<input>
、<textarea>
和<select>
这类表单元素会维持自身状态,并根据用户输入进行更新。但在 React 中,可变的状态通常保存在组件的状态属性中,并且只能用 setState() 方法进行更新。
我们通过使 React 变成一种单一数据源的状态来结合二者。React 负责渲染表单的组件仍然控制用户后续输入时所发生的变化。相应的,其值由 React 控制的输入表单元素称为“受控组件”。
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {value : ‘1‘}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange (event) {
this.setState({
value : event.target.value
})
}
handleSubmit (event) {
alert(‘name is ‘ + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<select value={this.state.value} onChange={this.handleChange}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
</label>
<input type="submit" value="Submit"></input>
</form>
)
};
}
ReactDOM.render(
<Form/>,
document.getElementById(‘root‘)
)
<input type=‘text‘>
、<textarea>
、<select>
类似,都是通过传入一个 value
属性来实现对组件的控制。
9.2 多个输入框
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
name : ‘‘,
age: 0
}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
const target = event.target;
const name = target.name;
const value = target.value;
this.setState({
[name] : value
})
}
handleSubmit(event) {
alert(‘name is ‘ + this.state.name + ‘, and age is ‘ + this.state.age);
event.preventDefault();
}
render () {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" name="name" value={this.state.name} onChange={this.handleChange}/>
</label>
<label>
age:
<input type="text" name="age" value={this.state.age} onChange={this.handleChange}/>
</label>
<input type="submit" value="Submit"/>
</form>
)
}
}
ReactDOM.render(
<Form/>,
document.getElementById(‘root‘)
)
当有多个受控的元素时,可以给每个元素添加一个 name 属性,来让处理函数 event.target.name 的值区分。
以上是关于React 基础语法的主要内容,如果未能解决你的问题,请参考以下文章