1. 组件定义
组件是React的核心概念,组件将应用的UI拆分成独立的、可复用的模块。
定义组件的两种方式:
(1)类组件:使用ES6 class
(2)函数组件:使用函数
使用class定义组件的两个条件:
(1)class继承自React.Component
(2)class内部必须定义render(),render()返回代表该组件UI的React元素。
1.1 基本组件
HelloWorld.js:
import React, { Component } from "react"class HelloWorld extends Component { render() { return (Hello World!
); }}export default HelloWorld;
Index.js:
import React from 'react';import ReactDOM from 'react-dom';import HelloWorld from './components/HelloWorld'ReactDOM.render(, document.getElementById('root'));
说明:ReactDOM.render()需要先导入react-dom库,这个库会完成组件所代表的虚拟DOM节点到浏览器的DOM节点的转换。
使用export default默认导出组件。
default表示可以在别的文件中使用import HelloWorld from './components/HelloWorld'导入这个模块;
如果没有default,则需要使用import { HelloWorld } from './components/HelloWorld'来导入模块。
1.2 组件的props
组件props用于把父组件中的数据或方法传递给子组件。
props是一个简单结构的对象,它包含的属性是由组件作为JSX标签所使用的属性组成。
示例(1):
import React, { Component } from "react"class HelloWorld extends Component { render() { return (Hello { this.props.name }!
); }}export default HelloWorld;
import React from 'react';import ReactDOM from 'react-dom';import HelloWorld from './components/HelloWorld'ReactDOM.render(, document.getElementById('root'));
示例(2):
TodoItem.js
import React, { Component } from 'react';class TodoItem extends React.Component { render() { const { id, title } = this.props; return (
TodoList.js
import React, { Component } from 'react';import TodoItem from './TodoItem';const data = [ { id: 1, title: 'ToDo' }, { id: 2, title: 'In Progress' }, { id: 3, title: 'Done' }]class TodoList extends Component { render() { return (
- { data.map((item) =>
index.js
import React from 'react';import ReactDOM from 'react-dom';import TodoList from './components/TodoList'ReactDOM.render(, document.getElementById('root'));
1.3 组件的state
组件的state是组件内部的姿态,state的变化最终将反映在组件UI的变化。
在组件的构造方法constructor中通过this.state定义组件的初始状态,并通过调用this.setState()改变组件状态,进而组件UI会随之重新渲染。
修改TodoItem.js
import React, { Component } from 'react';class TodoItem extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } handleClick() { let count = this.state.count; count++; this.setState({ count: count }); } render() { const { id, title } = this.props; return (
1.4 有状态组件和无状态组件
state用来反映组件内部状态的变化。
无状态组件:如果一个组件的内部状态是不变的,则用不到state。
有状态组件:如果一个组件的内部状态会发生变化,就需要使用state来保存变化。
示例:
HelloWorld.js
import React from 'react';function HelloWorld(props) { returnHello { props.name }!
;}export default HelloWorld;
注:由于使用了JSX,需要导入React。
index.js
import React from 'react';import ReactDOM from 'react-dom';import HelloWorld from './components/HelloWorld'ReactDOM.render(, document.getElementById('root'));
在使用无状态组件时,尽量定义函数组件。
在开发React应用时,要先思考哪些组件应该设计成有状态组件,哪些组件应该设计成无状态组件。并且,尽可能多的使用无状态组件,无状态组件不用关心状态变化,只聚焦于UI的展示,更容易复用。
React应用组件设计的一般思路:通过定义少数的有状态组件管理整个应用的状态变化,并且将状态通过props传递给其余的无状态组件,由无状态组件完成页面绝大部分UI的渲染。
有状态组件主要关注处理状态变化的业务逻辑,无状态组件主要关注组件的UI渲染。
1.5 属性校验和默认属性
1.5.1 属性校验
React提供PropTypes用于校验组件属性的类型。
import React from 'react';import PropTypes from 'prop-types'class HelloWorld extends React.Component { render(){ return (Hello { this.props.name }!
); }}HelloWorld.propTypes = { name: PropTypes.string}export default HelloWorld;
import React from 'react';import ReactDOM from 'react-dom';import HelloWorld from './components/HelloWorld'ReactDOM.render(, document.getElementById('root'));
若属性类型设置number,则报错提示。
import React from 'react';import PropTypes from 'prop-types'class HelloWorld extends React.Component { render(){ return (Hello { this.props.name }!
); }}HelloWorld.propTypes = { name: PropTypes.number}export default HelloWorld;
import React from 'react';import PropTypes from 'prop-types'class HelloWorld extends React.Component { render(){ return (Hello { this.props.name }!
); }}HelloWorld.propTypes = { name: PropTypes.string, style: PropTypes.shape ({ color: PropTypes.string, fontSize: PropTypes.number }).isRequired}export default HelloWorld;
import React from 'react';import ReactDOM from 'react-dom';import HelloWorld from './components/HelloWorld'ReactDOM.render(, document.getElementById('root'));
示例中,style是一个对象,包含两个属性color和fontSize,color是字符串类型,fontSize是数字类型。
如果属性是组件的必须属性,在PropTypes的类型属性上调用isRequired。
1.5.2 默认属性
React提供为组件属性指定默认值,组件defaultProps。当组件属性未被赋值时,组件会使用defaultProps定义的默认属性。
import React from 'react';class HelloWorld extends React.Component { render(){ return (Hello { this.props.name }!
); }}HelloWorld.defaultProps = { name: 'Libing'}export default HelloWorld;
import React from 'react';import ReactDOM from 'react-dom';import HelloWorld from './components/HelloWorld'ReactDOM.render(, document.getElementById('root'));
1.6 组件样式
为组件添加样式的方法主要有两种:外部样式表和内联样式。
1.6.1 外部CSS样式表
样式表引入的两种方式:
(1)在使用组件的HTML页面中通过标签引入
(2)把样式表当作一个模块,在使用该样式表的组件中,导入样式表文件
import './style.css'; // 相对路径
React元素要使用className代替class作为选择器。
/src/components/HelloWorld.css
.hello-world { color: red; font-size: 14px;}
/src/components/HelloWorld.js
import React from 'react';import './HelloWorld.css';class HelloWorld extends React.Component { render(){ return (Hello World!
); }}export default HelloWorld;
第一种引入样式表的方式常用于该样式表作为整个应用的所有组件(基础样式表),第二种引入样式表的方式常用于该样式表作用于某个组件(组件的私有样式)。
全局基础样式表要可以使用第二种方式引入,一般在应用的入口js文件中引入,如index.js。
1.6.2 内联样式
内联样式是一种CSS in JS的写法:将CSS写到JS文件中,用JS对象表示CSS,通过DOM类型节点的style属性引用样式对象。
import React from 'react';class HelloWorld extends React.Component { render(){ return (Hello World!
); }}export default HelloWorld;
style使用了两个大括号{
{}},第一个大括号表示style的值是一个JavaScript表达式,第二个大括号表示这个JavaScript表达式是一个对象。import React from 'react';class HelloWorld extends React.Component { render(){ const style = { color: 'red', fontSize: '14px' }; return (Hello World!
); }}export default HelloWorld;