创建方式

  1. //ES5 创建 class ( 过时方法 )
  2. import React from 'react'
  3. const A = React.createClass({
  4. render() { return ( <div>hi</div> )
  5. }
  6. })
  7. export default A
  8. //ES6 创建 class
  9. import React from 'react';
  10. class B extends React.Component {
  11. constructor(props) {
  12. super(props);
  13. }
  14. render() {
  15. return ( <div>hi</div> )
  16. }
  17. }
  18. export default B;
  19. // class XXX extends React.Component , constructor , super 请强行记忆
  20. // IE 不支持 ES6 怎么办?
  21. // 用 webpack+ babel将ES6翻译成ES5即可

组件动态数据

State(内部状态)

  1. import React,{Component} from 'react';
  2. class Hello extends Component{
  3. constructor(){
  4. super();
  5. //内部状态
  6. this.state = {
  7. name:'张三',
  8. }
  9. }
  10. //定义内部状态的第二种方式
  11. //state = {name:'张三'};
  12. changeName = ()=>{
  13. //修改状态的唯一方式setState
  14. this.setState({name:'李四'});
  15. }
  16. render(){
  17. const {name} = this.state;
  18. return <div>我叫:{name} <button onClick={this.changeName}>点我修改名字</button></div>
  19. }
  20. }

定义State

  1. //1. 在constructor中定义
  2. constructor(){
  3. super();
  4. //内部状态
  5. this.state = {
  6. name:'张三',
  7. }
  8. }
  9. //2. 直接在constructor外部定义
  10. state = {}

其实state就是当前类的一个实例属性而已

访问State

通过 this.state.xxx访问内部状态,一般在render方法中,我们倾向于先把状态中的值解构出来,在把他们渲染到
JSX中

修改State

  • 修改State的唯一方式是调用setState方法,该方法有两个作用,修改当前组建的State和更新页面
  • setState多次调用修改同一个属性时,render函数只会执行一次

    同步异步的问题
    • react18.0以前

      • 当在react事件体系(包括react生命周期钩子函数)里面调用setState方法时,它是异步的,否则,它是同步的
        1. class Hello extends Component {
        2. state = { name: '张三' };
        3. componentDidMount () {
        4. this.setState({ name: '李四' });//异步的
        5. console.log(this.state.name);//张三
        6. setTimeout(() => {//setTimeout并非react事件体系之内
        7. this.setState({ name: '王二麻子' });//同步的
        8. console.log(this.state.name);//王二麻子
        9. }, 1000);
        10. }
        11. render () {
        12. return <div></div>
        13. }
        14. }
    • react18.0以后

      • 全部是异步
      • 当setState是异步时,如果想要立刻获取修改后的值
        • async/await
        • 给setState传递第二个参数,即一个回调函数,该回调函数会在数据变化之后,并且界面更新之后在执行
          1. this.setState({ name: "李四" }, () => {
          2. console.log(this.state.name);//李四
          3. })
          参数的传递方式
  • 传入对象

  • 传入函数

    • 该函数会接受最新的state为参数,并返回一个对象
    • 因为setState是一个异步执行的,只有代码都执行完了,才会执行setState里面的东西
      1. this.setState(
      2. (state) => { //传入一个旧的(state)
      3. const n = state.n + 1 //修改旧的state生产新的
      4. console.log(n)
      5. return { n: n } //把新的 state return出去
      6. }
      7. );
      复杂state数据类型
  • 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 (

user.name: {this.state.user.name}
user.age: {this.state.user.age}
); } }

  1. <a name="NaO9i"></a>
  2. ### props(外部数据)
  3. <a name="srbKd"></a>
  4. #### 传递外部数据
  5. - 注意传字符串和传变量的写法是不一样的
  6. - 字符串
  7. - 变量
  8. - 类组件直接读取属性this. props.xx
  9. ```javascript
  10. import React from "react";
  11. import ReactDOM from "react-dom";
  12. import Son from './Son'
  13. function App() {
  14. const a = 10
  15. return (
  16. <div className="App">
  17. 父组件
  18. <Son message="儿子你好" /> //传 字符串 给类组件Son
  19. //<Son message={ a }> //传 变量 给类组件Son
  20. </div>
  21. );
  22. }
  1. import React, { Component } from 'react';
  2. import PropTypes from 'prop-types';
  3. export default class Son extends Component {
  4. //给组件的外部属性props设置默认值
  5. static defaultProps = {
  6. message: '默认message'
  7. }
  8. //语速组件属性值的类型
  9. static propTypes = {
  10. message: PropTypes.string,//规定要传递的message属性值,必须为string类型
  11. }
  12. render () {
  13. return <div>{this.props.message}</div>
  14. }
  15. }

react插槽(组件的children属性)

位于组件标签之间的内容就是插槽内容,要显示插槽内容需要在组件内部通过this.props.children渲染

  1. //parent组件
  2. import React, { Component } from 'react'
  3. import Child from './Child';
  4. export default class Parent extends Component {
  5. render () {
  6. return (
  7. <div>
  8. parent
  9. <Child>
  10. 这个child组件的插槽内容
  11. </Child>
  12. </div>
  13. )
  14. }
  15. }
  16. //child组件
  17. import React, { Component } from 'react'
  18. export default class Child extends Component {
  19. render () {
  20. return (
  21. <div>
  22. {this.props.children}
  23. </div>
  24. )
  25. }
  26. }

内外数据的区别

  • 内部状态可以自己修改
  • 外部属性是只读,不可修改
    • 如果这个外部属性是引用类型数据,不修改器引用本身,只是修改该引用下面的某个属性,是不会报错的,但是界面不会更新,如果你非要更新的话,可以使用this.forceUpdate
      1. import React, { Component } from 'react'
      2. class Parent extends Commponent {
      3. state = {
      4. name: '张三'
      5. }
      6. render () {
      7. const { name } = this.state;
      8. return <Hello msg="hello " obj={name} />
      9. }
      10. }
      11. class Hello extends Component {
      12. componentDidMount () {
      13. this.props.msg = 'new msg'//报错
      14. this.props.obj = {} //报错,引用本身变了
      15. this.props.obj.name = '李四';//不会报错,但是界面不会更新,除非接着调用
      16. this.forceUpdate()
      17. }
      18. render () {
      19. const { msg, obj } = this.props;
      20. return <div>msg:{msg} 我叫:{obj.name} </div>
      21. }
      22. }