第二章 React面向组件编程
一、基本理解和使用
1. 使用React开发者工具调试

2. 效果
2.1 函数式组件

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>1_函数式组件</title>
</head>
<body><div id="test"></div><script type="text/javascript" src="../js/react.development.js"></script><script type="text/javascript" src="../js/react-dom.development.js"></script><script type="text/javascript" src="../js/babel.min.js"></script><script type="text/babel">function MyComponent(){console.log(this); return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>}ReactDOM.render(<MyComponent/>,document.getElementById('test'))</script>
</body>
</html>
2.2 复习
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>类的基本知识</title>
</head>
<body><script type="text/javascript" >class Person {constructor(name,age){this.name = namethis.age = age}speak(){console.log(`我叫${this.name},我年龄是${this.age}`);}}class Student extends Person {constructor(name,age,grade){super(name,age)this.grade = gradethis.school = '小帽学堂'}speak(){console.log(`我叫${this.name},我年龄是${this.age},我读的是${this.grade}年级`);this.study()}study(){console.log('我很努力的学习');}}class Car {constructor(name,price){this.name = namethis.price = price}a = 1wheel = 4static demo = 100}const c1 = new Car('奔驰c63',199)console.log(c1);console.log(Car.demo);</script>
</body>
</html>
2.3 类式组件

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>2_类式组件</title>
</head>
<body><div id="test"></div><script type="text/javascript" src="../js/react.development.js"></script><script type="text/javascript" src="../js/react-dom.development.js"></script><script type="text/javascript" src="../js/babel.min.js"></script><script type="text/babel">class MyComponent extends React.Component {render(){console.log('render中的this:',this);return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>}}ReactDOM.render(<MyComponent/>,document.getElementById('test'))</script>
</body>
</html>
3. 注意
- 组件名必须首字母大写
- 虚拟DOM元素只能有一个根元素
- 虚拟DOM元素必须有结束标签
4. 渲染类组件标签的基本流程
- React内部会创建组件实例对象
- 调用render()得到虚拟DOM, 并解析为真实DOM
- 插入到指定的页面元素内部
二、组件三大核心属性1: state
1. 效果
2. 复习
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>原生事件绑定</title></head><body><button id="btn1">按钮1</button><button id="btn2">按钮2</button><button onclick="demo()">按钮3</button><script type="text/javascript" >const btn1 = document.getElementById('btn1')btn1.addEventListener('click',()=>{alert('按钮1被点击了')})const btn2 = document.getElementById('btn2')btn2.onclick = ()=>{alert('按钮2被点击了')}function demo(){alert('按钮3被点击了')}</script></body>
</html>
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>类方法中的this指向</title></head><body><script type="text/javascript" >class Person {constructor(name,age){this.name = namethis.age = age}study(){console.log(this);}}const p1 = new Person('tom',18)p1.study() const x = p1.studyx()</script></body>
</html>
3. 理解
- state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
- 组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)
4. 强烈注意
- 组件中render方法中的this为组件实例对象
- 组件自定义的方法中this为undefined,如何解决?
- 强制绑定this: 通过函数对象的bind()
- 箭头函数
- 状态数据,不能直接修改或更新
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>state</title>
</head>
<body><div id="test"></div><script type="text/javascript" src="../js/react.development.js"></script><script type="text/javascript" src="../js/react-dom.development.js"></script><script type="text/javascript" src="../js/babel.min.js"></script><script type="text/babel">class Weather extends React.Component{constructor(props){console.log('constructor');super(props)this.state = {isHot:false,wind:'微风'}this.changeWeather = this.changeWeather.bind(this)}render(){console.log('render');const {isHot,wind} = this.statereturn <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>}changeWeather(){console.log('changeWeather');const isHot = this.state.isHotthis.setState({isHot:!isHot})console.log(this);}}ReactDOM.render(<Weather/>,document.getElementById('test'))</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>state简写方式</title>
</head>
<body><div id="test"></div><script type="text/javascript" src="../js/react.development.js"></script><script type="text/javascript" src="../js/react-dom.development.js"></script><script type="text/javascript" src="../js/babel.min.js"></script><script type="text/babel">class Weather extends React.Component{state = {isHot:false,wind:'微风'}render(){const {isHot,wind} = this.statereturn <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>}changeWeather = ()=>{const isHot = this.state.isHotthis.setState({isHot:!isHot})}}ReactDOM.render(<Weather/>,document.getElementById('test'))</script>
</body>
</html>
三、组件三大核心属性2: props
1. 效果
- 需求: 自定义用来显示一个人员信息的组件
- 姓名必须指定,且为字符串类型;
- 性别为字符串类型,如果性别没有指定,默认为男
- 年龄为字符串类型,且为数字类型,默认值为18

2. 理解
- 每个组件对象都会有props(properties的简写)属性
- 组件标签的所有属性都保存在props中
3. 作用
- 通过标签属性从组件外向组件内传递变化的数据
- 注意: 组件内部不要修改props数据
4. 编码操作
4.1 内部读取某个属性值
this.props.name
4.2 对props中的属性值进行类型限制和必要性限制
- 第一种方式(React v15.5 开始已弃用):
Person.propTypes = {name: React.PropTypes.string.isRequired,age: React.PropTypes.number
}
- 第二种方式(新):使用prop-types库进限制(需要引入prop-types库)
Person.propTypes = {name: PropTypes.string.isRequired,age: PropTypes.number
}
4.3 扩展属性: 将对象的所有属性通过props传递
<Person {...person}/>
4.4 默认属性值
Person.defaultProps = {age: 18,sex:'男'
}
4.5 组件类的构造函数
constructor(props){super(props)console.log(props)
}
5. 代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>props基本使用</title>
</head>
<body><div id="test1"></div><div id="test2"></div><div id="test3"></div><script type="text/javascript" src="../js/react.development.js"></script><script type="text/javascript" src="../js/react-dom.development.js"></script><script type="text/javascript" src="../js/babel.min.js"></script><script type="text/babel">class Person extends React.Component{render(){const {name,age,sex} = this.propsreturn (<ul><li>姓名:{name}</li><li>性别:{sex}</li><li>年龄:{age+1}</li></ul>)}}ReactDOM.render(<Person name="jerry" age={19} sex="男"/>,document.getElementById('test1'))ReactDOM.render(<Person name="tom" age={18} sex="女"/>,document.getElementById('test2'))const p = {name:'老刘',age:18,sex:'女'}ReactDOM.render(<Person {...p}/>,document.getElementById('test3'))</script>
</body>
</html>
<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>展开运算符</title></head><body><script type="text/javascript" >let arr1 = [1,3,5,7,9]let arr2 = [2,4,6,8,10]console.log(...arr1); let arr3 = [...arr1,...arr2]function sum(...numbers){return numbers.reduce((preValue,currentValue)=>{return preValue + currentValue})}console.log(sum(1,2,3,4));let person = {name:'tom',age:18}let person2 = {...person}person.name = 'jerry'console.log(person2);console.log(person);let person3 = {...person,name:'jack',address:"地球"}console.log(person3);</script></body>
</html>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>对props进行限制</title>
</head>
<body><div id="test1"></div><div id="test2"></div><div id="test3"></div><script type="text/javascript" src="../js/react.development.js"></script><script type="text/javascript" src="../js/react-dom.development.js"></script><script type="text/javascript" src="../js/babel.min.js"></script><script type="text/javascript" src="../js/prop-types.js"></script><script type="text/babel">class Person extends React.Component{render(){const {name,age,sex} = this.propsreturn (<ul><li>姓名:{name}</li><li>性别:{sex}</li><li>年龄:{age+1}</li></ul>)}}Person.propTypes = {name:PropTypes.string.isRequired, sex:PropTypes.string,age:PropTypes.number,speak:PropTypes.func,}Person.defaultProps = {sex:'男',age:18 }ReactDOM.render(<Person name={100} speak={speak}/>,document.getElementById('test1'))ReactDOM.render(<Person name="tom" age={18} sex="女"/>,document.getElementById('test2'))const p = {name:'老刘',age:18,sex:'女'}ReactDOM.render(<Person {...p}/>,document.getElementById('test3'))function speak(){console.log('我说话了');}</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>props的简写形式</title>
</head>
<body><div id="test1"></div><div id="test2"></div><div id="test3"></div><script type="text/javascript" src="../js/react.development.js"></script><script type="text/javascript" src="../js/react-dom.development.js"></script><script type="text/javascript" src="../js/babel.min.js"></script><script type="text/javascript" src="../js/prop-types.js"></script><script type="text/babel">class Person extends React.Component{constructor(props){super(props)console.log('constructor',this.props);}static propTypes = {name:PropTypes.string.isRequired, sex:PropTypes.string,age:PropTypes.number,}static defaultProps = {sex:'男',age:18 }render(){const {name,age,sex} = this.propsreturn (<ul><li>姓名:{name}</li><li>性别:{sex}</li><li>年龄:{age+1}</li></ul>)}}ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1'))</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>函数组件使用props</title>
</head>
<body><div id="test1"></div><div id="test2"></div><div id="test3"></div><script type="text/javascript" src="../js/react.development.js"></script><script type="text/javascript" src="../js/react-dom.development.js"></script><script type="text/javascript" src="../js/babel.min.js"></script><script type="text/javascript" src="../js/prop-types.js"></script><script type="text/babel">function Person (props){const {name,age,sex} = propsreturn (<ul><li>姓名:{name}</li><li>性别:{sex}</li><li>年龄:{age}</li></ul>)}Person.propTypes = {name:PropTypes.string.isRequired, sex:PropTypes.string,age:PropTypes.number,}Person.defaultProps = {sex:'男',age:18 }ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1'))</script>
</body>
</html>