创建方式
//ES5 创建 class ( 过时方法 )import React from 'react'const A = React.createClass({render() { return ( <div>hi</div> )}})export default A//ES6 创建 classimport React from 'react';class B extends React.Component {constructor(props) {super(props);}render() {return ( <div>hi</div> )}}export default B;// class XXX extends React.Component , constructor , super 请强行记忆// IE 不支持 ES6 怎么办?// 用 webpack+ babel将ES6翻译成ES5即可
组件动态数据
State(内部状态)
import React,{Component} from 'react';class Hello extends Component{constructor(){super();//内部状态this.state = {name:'张三',}}//定义内部状态的第二种方式//state = {name:'张三'};changeName = ()=>{//修改状态的唯一方式setStatethis.setState({name:'李四'});}render(){const {name} = this.state;return <div>我叫:{name} <button onClick={this.changeName}>点我修改名字</button></div>}}
定义State
//1. 在constructor中定义constructor(){super();//内部状态this.state = {name:'张三',}}//2. 直接在constructor外部定义state = {}
访问State
通过 this.state.xxx访问内部状态,一般在render方法中,我们倾向于先把状态中的值解构出来,在把他们渲染到
JSX中
修改State
- 修改State的唯一方式是调用setState方法,该方法有两个作用,修改当前组建的State和更新页面
setState多次调用修改同一个属性时,render函数只会执行一次
同步异步的问题
react18.0以前
- 当在react事件体系(包括react生命周期钩子函数)里面调用setState方法时,它是异步的,否则,它是同步的
class Hello extends Component {state = { name: '张三' };componentDidMount () {this.setState({ name: '李四' });//异步的console.log(this.state.name);//张三setTimeout(() => {//setTimeout并非react事件体系之内this.setState({ name: '王二麻子' });//同步的console.log(this.state.name);//王二麻子}, 1000);}render () {return <div></div>}}
- 当在react事件体系(包括react生命周期钩子函数)里面调用setState方法时,它是异步的,否则,它是同步的
react18.0以后
传入对象
传入函数
setState是对state进行了浅合并,只会修改相同的属性,保留其他属性.。因为底层使用
Object.assign()- 当state的数据为复杂数据类型,如对象时,setState则修改不了内层数据
- 需要使用
Obiect. assign或者...操作符(展开操作符) ```javascript import React from “react”; import ReactDOM from “react-dom”;
import “./styles.css”;
function App() { return (
//类组件 复杂 state
class Son extends React.Component {
constructor() {
super();
this.state = {
n: 0,
m: 0,
user: { //这是第二层
name: “frank”,
age: 18
}
};
}
changeUser() {
this.setState({ //这是第二层,不会自动合并
// m 和 n 不会被置空
user: {
name: “jack”
// age 被置空 不会自动沿用上面这一层
}
//正确写法一
user: {
…this.state.user, //必须加上这一句age就不会被置空
name: “jack” //这样修改时候就会自动使用上一层的
}
//正确写法二
const user = Object.assign({}, this.state.user)
user.name = “jack”
this.setState({
user: user
})
//正确写法三
const {user} = this.state
user.name = “jack”
this.setState({user})
});
}
render() {
return (
<a name="NaO9i"></a>### props(外部数据)<a name="srbKd"></a>#### 传递外部数据- 注意传字符串和传变量的写法是不一样的- 字符串- 变量- 类组件直接读取属性this. props.xx```javascriptimport React from "react";import ReactDOM from "react-dom";import Son from './Son'function App() {const a = 10return (<div className="App">父组件<Son message="儿子你好" /> //传 字符串 给类组件Son//<Son message={ a }> //传 变量 给类组件Son</div>);}
import React, { Component } from 'react';import PropTypes from 'prop-types';export default class Son extends Component {//给组件的外部属性props设置默认值static defaultProps = {message: '默认message'}//语速组件属性值的类型static propTypes = {message: PropTypes.string,//规定要传递的message属性值,必须为string类型}render () {return <div>{this.props.message}</div>}}
react插槽(组件的children属性)
位于组件标签之间的内容就是插槽内容,要显示插槽内容需要在组件内部通过this.props.children渲染
//parent组件import React, { Component } from 'react'import Child from './Child';export default class Parent extends Component {render () {return (<div>parent<Child>这个child组件的插槽内容</Child></div>)}}//child组件import React, { Component } from 'react'export default class Child extends Component {render () {return (<div>{this.props.children}</div>)}}
内外数据的区别
- 内部状态可以自己修改
- 外部属性是只读,不可修改
- 如果这个外部属性是引用类型数据,不修改器引用本身,只是修改该引用下面的某个属性,是不会报错的,但是界面不会更新,如果你非要更新的话,可以使用
this.forceUpdateimport React, { Component } from 'react'class Parent extends Commponent {state = {name: '张三'}render () {const { name } = this.state;return <Hello msg="hello " obj={name} />}}class Hello extends Component {componentDidMount () {this.props.msg = 'new msg'//报错this.props.obj = {} //报错,引用本身变了this.props.obj.name = '李四';//不会报错,但是界面不会更新,除非接着调用this.forceUpdate()}render () {const { msg, obj } = this.props;return <div>msg:{msg} 我叫:{obj.name} </div>}}
- 如果这个外部属性是引用类型数据,不修改器引用本身,只是修改该引用下面的某个属性,是不会报错的,但是界面不会更新,如果你非要更新的话,可以使用
