React入门 (1)

886 阅读6分钟

一、概念

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

  1. 在React中,推荐采用JSX来编写页面元素;JSX执行更快,因为它在编译成 JavaScript 代码后进行了优化。
  2. 在项目中,如果我们需要使用 JSX,则 <script> 标签的 type 属性需要设置为 text/babel。
  3. 由于 JSX 就是 JavaScript,一些标识符像 class 和 for 不建议作为 XML 属性名。作为替代,React DOM 使用 classNamehtmlFor 来做对应的属性。同时,添加自定义属性需要使用 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 将其传递到子组件上。