React -- state props

目录

起步

hello, react

jsx 语法规则

React 组件类型

函数式组件(适用于简单组件)

类式组件(适用于复杂组件)

state

props

 propTypes (类型检测)

es6 类知识点回顾


起步

hello, react

引入 react 核心库:

<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>

创建容器:

<body>
  <div id="example"></div>
</body>

创建虚拟DOM并渲染到页面:

<script type="text/babel"> //此处一定要用 babel
  
  // 1. 创建虚拟 DOM
  const VDOM = <h1>hello, react!</h1>
  // 2. 渲染虚拟 DOM 到页面
  ReactDOM.render(VDOM, document.getElementById('example'))

</script>

jsx 语法规则

1. 创建虚拟 dom 时不能加引号,且根节点只有一个;
2. 标签中有 js表达式/变量 时用 {};
3. 标签:行内样式:style={ { key:value, key:value } }
               class命名:className
4. 标签必须闭合;
5. 标签首字母:
    (1). 小写字母开头:将该标签转为html中同名元素,若html中无该标签对应的同名元素则报错
    (2). 大写字母开头:react 渲染对应的组件,若组件未定义则报错

<script type="text/babel">

  const title = '标题'
  const arr = ['a', 'b', 'c']

  const VDOM = (
    <div>

      <h1 style={ {color:'red'} }>hello, react</h1>
      <p className="title">{ title }</p>
      <input type="text"/>

      <ul>
        {
          arr.map((item, index) => {
            return <li key={index}>{ item }</li>
          })
        }
      </ul>

    </div>
  )

  ReactDOM.render(VDOM, document.getElementById('example'))

</script>

React 组件类型

函数式组件(适用于简单组件)

执行了 ReactDOM.render(<MyComponent />, ...)之后,发生了什么?
1. React 解析组件标签,找到了 MyComponent 组件;
2. 发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转化为真实DOM,展示在页面中。

<script type="text/babel">
  
  // 创建 MyComponent 组件
  function MyComponent () {
    console.log(this) // undefined, 因为babel编译后开启了严格模式
    return (
        <div>
          <h2>I am FunctionComponent</h2>
          <p>I like vue</p>  
        </div>
      )
  }

  ReactDOM.render(<MyComponent />, document.getElementById('example'))

</script>

类式组件(适用于复杂组件)

执行了 ReactDOM.render(<MyComponent />, ...)之后,发生了什么?
1. React 解析组件标签,找到了 MyComponent 组件;
2. 发现组件是使用类定义的,随后 new 出来该类的实例,并通过该实例调用到原型链上的 render 方法;
3. 将 render 返回的虚拟DOM转为真实DOM,展示在页面中。

<script type="text/babel">

  class MyComponent extends React.Component {
    render () {
      console.log(this) // MyComponent 实例对象
      return (
        <div>
          <h2>I am ClassComponent</h2>
          <p>welcome</p>  
        </div>
      )
    }
  }

  ReactDOM.render(<MyComponent />, document.getElementById('example'))

</script>

state

<script type="text/babel">

  class MyComponent extends React.Component {
    constructor (props) {
      super(props)
      this.state = { // 初始化状态
        isHappy: true
      }
    }
    render () {
      console.log(this) // new出实例后自动调用render,所以this为:MyComponent实例对象

      const { isHappy } = this.state
      return <h2 onClick={this.changeMood}>我今天很{ isHappy ? '开心' : '不开心' }</h2>
    }
    changeMood () {
      console.log(this) // onClick 事件的回调,并非通过new实例调用,所以this为:undefined
    }
  }

  ReactDOM.render(<MyComponent />, document.getElementById('example'))

</script>

为了让 changeMood 方法能够指向 this,我们在 constructor 构造器中,对方法进行绑定:
在方法内用 setState({}) 改变初始化state:

<script type="text/babel">

  class MyComponent extends React.Component {
    constructor (props) { // 调用 1 次
      super(props) 
      this.state = {
        isHappy: true
      }
      this.changeMood = this.changeMood.bind(this) // 将原型上的方法绑定到实例对象,解决方法中this的指向问题
    }
    render () { // 调用 1+n 次
      const { isHappy } = this.state
      return <h2 onClick={this.changeMood}>我今天很{ isHappy ? '开心' : '不开心' }</h2>
    }
    changeMood () { // 调用 n 次
      const { isHappy } = this.state

      this.setState({
        isHappy: !isHappy
      })

      // 注意:state不可以直接修改!!state不可以直接修改!!state不可以直接修改!!
      //this.state.isHappy = !isHappy  // 这个是错误写法!!!
    }
  }

  ReactDOM.render(<MyComponent />, document.getElementById('example'))

</script>

那么问题来了,如果每次想在方法中绑定 this 都需要在constructor中bind(this)的话,太过于繁琐,所以采用如下写法:

<script type="text/babel">

  class MyComponent extends React.Component {
    
    state = {
      isHappy: true
    }

    render () {
      const { isHappy } = this.state
      return <h2 onClick={this.changeMood}>我今天很{ isHappy ? '开心' : '不开心' }~</h2>
    }

    changeMood = () => {
      const { isHappy } = this.state

      this.setState({
        isHappy: !isHappy
      })

    }
  }

  ReactDOM.render(<MyComponent />, document.getElementById('example'))

</script>

1. 在 React 中,构造函数仅用于以下两种情况:
    (1). 通过给 this.state 赋值对象来初始化内部 state;
    (2). 为事件处理函数绑定实例。

【注意】!!在 constructor() 函数中不要调用 setState() 方法,如果你的组件需要使用内部的state, 请直接在构造器中为 this.state 赋值初始 state

constructor (props) {
   super(props)
   this.state = { counter: 0 } // 不要在这里使用 this.setState()
   this.handleClick = this.handleClick.bind(this)
}

props

语法:<MyComponent  {...propsObject} />

<script type="text/babel">

  class MyComponent extends React.Component {
    render () {
      const { name, age, sex } = this.props // 取到组件中传入的 props 值
      return (
        <div>
          <ul>
            <li>姓名:{ name }</li>  
            <li>年龄:{ age + 1 }</li>  
            <li>性别:{ sex }</li>  
          </ul>
        </div>
      )
    }
  }

  // age为number类型,用{}
  // ReactDOM.render(<MyComponent name="laowang" age={18} sex="male" />, document.getElementById('example'))

  const info = { name: "Lucy", age: 18, sex: "female" }
  ReactDOM.render(<MyComponent {...info} />, document.getElementById("example"))

</script>

 propTypes (类型检测)

引入 CDN

<script src="https://cdn.bootcdn.net/ajax/libs/prop-types/15.5.6/prop-types.js"></script>

在类中写入static静态规则:

<script type="text/babel">

  class MyComponent extends React.Component {
    static propTypes = { // 类型
      name: PropTypes.string.isRequired,
      age: PropTypes.number,
      sex: PropTypes.string,
      speak: PropTypes.func // 函数
    }

    
    static defaultProps = { // 默认值
      sex: 'female'
    }

    render () {
      ...
    }
  }
  const info = { name: "Marry", age: '18' } // 未传入sex,用 defaultProps 中sex默认值
  ReactDOM.render(<MyComponent {...info} />, document.getElementById("example"))
  
</script>

由于传入的age类型不正确,控制台报错:

===============================================================

es6 类知识点回顾

1. p1.sleep() 是通过 People 实例调用的方法,所以this指向People实例;
    p2() 相当于直接用一个函数体执行,相当于指向 window,而类中的方法默认开启了局部的严格模式,所以 this 打印为 undefined。

class People {
    constructor (name, age) {
      this.name = name
      this.age = age
    }

    sleep () {
      console.log(this)
    }

  }

  var p1 = new People('张三', 18)
  p1.sleep() // People 实例

  var p2 = p1.sleep
  p2() // undefined

p2()this打印为undefined, 因为sleep方法在原型上,不在new实例对象上;p1.sleep() 找的是原型上的方法,this打印情况如下:

<script>

  class People {
    constructor (name, age) {
      this.name = name
      this.age = age
      this.sleep = this.sleep.bind(this)
    }

    sleep () {
      console.log(this)
    }
  }

  var p1 = new People('张三', 18)
  p1.sleep()
  var p2 = p1.sleep
  p2()
  
</script>

p1.sleep() 和  p2() this打印情况如下:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值