一、概念
React.js 是一个用于构建用户界面的 JavaScript 库,页面的元素由jsx编写生成。
二、特点
- 声明式:创建交互式 UI 变得轻而易举。为你应用的每一个状态设计简洁的视图,当数据改变时 React 能有效地更新并正确地渲染组件。
- 组件化:组件有函数式组件、类组件两种,将巨大的业务逻辑拆分成一个个逻辑清晰的小组件。
- JSX:JSX 是 JavaScript 语法的扩展,JS 使用 XML 语法来编写用户界面,充分利用 JS 强大的特性来操作用户界面
(编译时,将XML语法转译成js,js通过createElement生成元素)。 - 数据更新:与Vue.js数据的双向绑定特性不同,React中数据的改变均由
setState触发;表单也没办法直接获取输入的数据,必须监听输入change事件,从而由setState触发。 - 高效:React通过对DOM的模拟
(虚拟DOM),最大限度地减少与DOM的交互。
三、构建项目
在npm上使用 create-react-app 快速构建 React 项目,使用 Babel和 Webpack,之后的实践均可在项目中编写并在浏览器实时预览。
cnpm install -g create-react-app
create-react-app my-app
Create React App 脚手架使用 Webpack Development Server(WDS)作为开发服务器,因此编辑代码后只需保存文件,React 应用就会自动刷新。
四、元素渲染
与浏览器的 DOM 元素不同,React 当中的元素事实上是普通的JS对象(虚拟DOM),React DOM 可以确保浏览器 DOM 的数据内容与 React 元素保持一致。
ReactDOM.render 方法接收两个参数:
- 根组件
- 待挂载的 DOM 节点
1、将元素渲染到 DOM 中
// 在一个 HTML 页面中添加一个 id="example" 的 <div>,为根节点
<div id="example"></div>
// 利用jsx编写元素,通过ReactDOM.render() 的方法来将其渲染到页面上
const element = <h1>Hello, world!</h1>;
ReactDOM.render(
element,
document.getElementById('example')
);
2、更新元素渲染
React 元素都是不可变的。当元素被创建之后无法改变其内容或属性的。 目前更新界面的唯一办法是创建一个新的元素,然后将它传入 ReactDOM.render() 方法。
// 创建一个 React.Component 的 ES6 类
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>现在是 {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('example')
);
}
//通过 setInterval() 方法,每秒钟调用一次 ReactDOM.render()
setInterval(tick, 1000);
React DOM 首先会比较元素内容先后的不同,而在渲染过程中只会更新改变了的部分。
五、JSX
- 在React中,推荐采用JSX来编写页面元素;JSX执行更快,因为它在编译成 JavaScript 代码后进行了优化。
- 在项目中,如果我们需要使用 JSX,则
<script>标签的 type 属性需要设置为 text/babel。 - 由于 JSX 就是 JavaScript,一些标识符像 class 和 for 不建议作为 XML 属性名。作为替代,React DOM 使用
className和htmlFor来做对应的属性。同时,添加自定义属性需要使用data-前缀。
<div>Hello, World</div> 是一段 JSX 代码,它最终会被 Babel 转译成:
React.createElement(
'div',
null,
'Hello, World'
)
React.createElement() 接收三个参数:
- JSX 元素标签
- JSX 元素接收的属性,对象Object
- JSX 元素包裹的内容(子级)
React.createElement()会检查参数以确保代码不会产生 BUG并创建React Element对象;React 将会接收这些对象并构建 DOM。
{
type: 'div',
props: {
children: 'Hello, World'
}
};
JSX 中使用 JavaScript 表达式,变量值写在花括号 {} 中:
// 变量
var content = 'hjj';
ReactDOM.render(
<div>
<h1>{1+1}</h1>
<h1>{content}</h1>
</div>
,
document.getElementById('example')
);
// 三目元算符,JSX 中不能使用 if else 语句
<h1>{i == 1 ? 'True!' : 'False'}</h1>
// 数组
var arr = [
<h1>菜鸟教程</h1>,
<h2>学的不仅是技术,更是梦想!</h2>,
];
ReactDOM.render(
<div>{arr}</div>,
document.getElementById('example')
);
// 列表,不建议使用索引index作为key来进行排序,因为这会导致渲染变得很慢;key 值不会作为 props 传递给子组件,React 会在编译组件时将 key 值从 props 中排除。
const todoList = ["图雀", "图雀写作工具", "图雀社区", "图雀文档"];
const list = {todoList.map((todo, index) => (
<Todo content={todo} key={index} />
))}
ReactDOM.render(
<div>
<ul>{list}</ul>
</div>,
document.getElementById('example')
);
// 条件渲染
const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
<div>
{messages.length > 0 &&
<h2>
您有 {messages.length} 条未读信息。
</h2>
}
</div>,
document.getElementById('example')
);
// 样式,推荐使用 camelCase 语法来设置内联样式. React 会在指定元素数字后自动添加 px
var myStyle = {
fontSize: 100,
color: '#FF0000'
};
ReactDOM.render(
<h1 style = {myStyle}>菜鸟教程</h1>,
document.getElementById('example')
);
// JSX 中使用 JSX,编写任意层次的 HTML 结构
render() {
const element = <li>Hello, World</li>
return (
<div>
<ul>
{element}
</ul>
</div>
)
}
// JSX 中添加节点属性,所有的属性都要更换成驼峰式命名,比如 onclick 要改成 onClick
const element = <div dataIndex="0">Hello, World</div>;
// 注释,需要写在花括号中
{/*注释...*/}
六、组件
1、函数定义(函数式组件)
默认接收一个 props 参数,然后返回一段 JSX。。
function HelloMessage(props) {
return <h1>Hello {props.name}!</h1>;
}
const element = <HelloMessage name="Runoob"/>;
2、ES6 class 定义(类组件)
通过继承自 React.Component 的类来代表一个组件,在 render 方法里面返回需要渲染的 JSX。
class Todo extends React.Component {
render() {
return <li>Hello, {this.props.content}</li>;
}
}
<Todo content="图雀" />
原生 HTML 元素名以小写字母开头,而自定义的 React 类名以大写字母开头。
3、复合组件
// 创建多个组件来合成一个组件,即把组件的不同功能点进行分离
function Name(props) {
return <h1>网站名称:{props.name}</h1>;
}
function Url(props) {
return <h1>网站地址:{props.url}</h1>;
}
function App() {
return (
<div>
<Name name="菜鸟教程" />
<Url url="http://www.runoob.com" />
</div>
);
}
七、State、Props
1、State
可变状态,React 把组件看成是一个状态机(State Machines),通过与用户的交互实现不同状态,然后渲染 UI让用户界面和数据保持一致。
class Clock extends React.Component {
constructor(props) {
super(props);// props 属性
this.state = {date: new Date()};// 定义和初始化 State
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>现在是 {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
更新 state:this.setState 方法,从而使得网页内容在渲染之后还能变化。
关于 this.setState 我们需要注意以下几点:
1)不能通过直接修改 this.state 的方式来更新 state:
this.state.todoList = newTodoList;
2)State 的更新是合并更新的:
// 原 `state` 是这样的:
constructor(props) {
super(props);
this.state = {todoList: [],nowTodo: '',};
}
// 调用 `this.setState()` 方法来更新 `state`:
this.setState({ nowTodo: "Hello, 图雀" });
// React 将会合并更新,即将 `nowTodo` 的新内容合并进原 `this.state`,当更新之后,我们的 `this.state` 将会是这样的,不会因为只单独设置了 `nowTodo` 的值,就将 `todoList` 给覆盖掉。:
this.state = { todoList: [], nowTodo: "Hello, 图雀" };
2、Props
不可变属性,它是一个对象,通常为父组件传参或默认属性。
function Todo(props) {
return (
<li>Hello, {props.content}</li>
)
}
<Todo content="图雀" />
Props 验证使用 propTypes,它可以保证我们的应用组件被正确使用,React.PropTypes 提供很多验证器 (validator) 来验证传入数据是否有效。当向 props 传入无效数据时,JavaScript 控制台会抛出警告。
var title = 123;// 属性 title 是必须的且是字符串,非字符串类型会自动转换为字符串
class MyTitle extends React.Component {
render() {
return (
<h1>Hello, {this.props.title}</h1>
);
}
}
MyTitle.propTypes = {
title: PropTypes.string
};
ReactDOM.render(
<MyTitle title={title} />,
document.getElementById('example')
);
默认 Props
class HelloMessage extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
HelloMessage.defaultProps = {// 通过组件类的 defaultProps 属性为 props 设置默认值
name: 'Runoob'
};
const element = <HelloMessage/>;
3、区别
- state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。
- 组合使用 state 和 props,在父组件中设置 state, 并通过在子组件上使用 props 将其传递到子组件上。