React 入门知识

2018-01-16  本文已影响34人  风之化身呀

本文记录React框架入门知识

安装及启动

npm i -g create-react-app             //全局安装react的cli
create-react-app hello-react             //hello-react是项目名
cd hello-react & npm start                //启动项目

基本用法

初始完后,src/index.js内容如下:

import React, { Component } from 'react'      //必须引入
import ReactDOM from 'react-dom'              //做浏览器应用时必须引入
import './index.css'                                        //引入样式文件
class Header extends Component {
  render () {                                                   // 必须有render函数,返回的是JSX形式模板
    return (
      <div>
        <h1>Hello React</h1>
      </div>
    )
  }
}

ReactDOM.render(                                     //ReactDOM帮忙渲染到指定节点
  <Header />,
  document.getElementById('root')
)

所以基本有三个必要步骤:1、引库;2、写组件的render函数;3、ReactDOM渲染到页面。
重要语法点:

...
render () {         //ES6函数简写形式
  return (
    <div>
      <div>第一个</div>
      <div>第二个</div>
    </div>
  )
}
...
render () {
  const word = 'is good'
  return (
    <div>
      <h1>Hello World {word}</h1>      // vue中是双大括号'{{}}'
    </div>
  )
}
render () {
  const className = 'header'
  return (
    <div className={className}>
      <h1>Hello World</h1>
    </div>
  )
}
render () {
  const isGoodWord = true
  const goodWord = <strong> is good</strong>    // 引号都不能加,加了就当字符串了,最重要的是这里可以嵌套插值!!!!
  const badWord = <span> is not good</span>
  return (
    <div>
      <h1>
        Hello World
        {isGoodWord ? goodWord : badWord}
      </h1>
    </div>
  )
}
class Title extends Component {
  handleClickOnTitle () {
    console.log('Click on title.')
  }
  render () {
    return (
      <h1 onClick={this.handleClickOnTitle}>Hello World</h1>
    )
  }
}

2、事件属性名都必须要用驼峰命名法,且只能用在普通的 HTML 的标签上,不能用在组件标签上,如:<Header onClick={this.handleClick} />是无效的。
3、event对象会被传入处理函数,该对象经过React自己的封装,与原生event对象差异不大
4、一般在某个类的实例方法里面的 this 指的是这个实例本身,但react不是,也就是在实例方法里拿不到当前实例,所以需要借助bind来实现。这个模式在react中非常常见。
还可以利用bind来传参数,注意此时事件处理器参数顺序:先接受参数,最后是event

class Title extends Component {
  handleClickOnTitle (param,e) {
    console.log(this)
  }
  render () {
    return (
      <h1 onClick={this.handleClickOnTitle.bind(this,param)}>Hello World</h1>
    )
  }
}
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import './index.css'
class LikeButton extends Component {
  constructor () {
    super()                                           //构造函数中调父元素初始化方法
    this.state = {                                  // 添加自身状态属性
          name: 'Tomy',
          isLiked: false
     }         
  }

  handleClickOnLikeButton () {
    this.setState({                     //只能通过setState来改变状态,不能直接this.isLiked=××
      isLiked: !this.state.isLiked   //只设置需要更新的属性,其他属性保持不变,如name
    })
  }
  render () {
    return (
      <button onClick={this.handleClickOnLikeButton.bind(this)}>
        {this.state.isLiked ? '取消' : '点赞'} 👍
      </button>
    )
  }
}

setState接受函数参数和对象参数。当是对象参数时,多个setState不是实时更新,而是react帮你存在队列里一起更新(为了效率);当是函数参数时,setState操作是实时更新的。

  handleClickOnLikeButton () {
    this.setState((prevState) => {
      return { count: 0 }
    })
    this.setState((prevState) => {
      return { count: prevState.count + 1 } // 上一个 setState 的返回是 count 为 0,当前返回 1
    })
    this.setState((prevState) => {
      return { count: prevState.count + 2 } // 上一个 setState 的返回是 count 为 1,当前返回 3
    })
    // 最后的结果是 this.state.count 为 3
  }

当进行多次 setState,实际上组件只会重新渲染一次,而不是多次;这是因为在 React.js 内部会把 JavaScript 事件循环中的消息队列的同一个消息中的 setState 都进行合并以后再重新渲染组件

class LikeButton extends Component {
  static defaultProps = {
    likedText: '取消',
    unlikedText: '点赞'
  }

  constructor () {
    super()
    this.state = { isLiked: false }
  }

  handleClickOnLikeButton () {
    this.setState({
      isLiked: !this.state.isLiked
    })
  }

  render () {
    return (
      <button onClick={this.handleClickOnLikeButton.bind(this)}>
        {this.state.isLiked
          ? this.props.likedText
          : this.props.unlikedText} 👍
      </button>
    )
  }
}

1、为了使得组件的可定制性更强,在使用组件的时候,可以在标签上加属性来传入配置参数。
2、组件可以在内部通过 this.props 获取到配置参数,组件可以根据 props 的不同来确定自己的显示形态,达到可配置的效果。
3、可以通过给组件添加类属性 defaultProps 来配置默认参数。
4、props 一旦传入,你就不可以在组件内部对它进行修改。但是你可以通过父组件主动重新渲染的方式来传入新的 props,从而达到更新的效果。

无状态组件(函数式组件):只能接收props为参数,只提供render的返回值

const HelloWorld = props=> {
  const sayHi = event => alert('Hello World')
  return (
    <div onClick={sayHi}>Hello World</div>
  )
}
class Index extends Component {
  render () {
    return (
      <div>
        {users.map((user,index) => {            //map不改变原数组
          return (
            <div key={index}>
              <div>姓名:{user.username}</div>
              <div>年龄:{user.age}</div>
              <div>性别:{user.gender}</div>
              <hr />
            </div>
          )
        })}
      </div>
    )
  }
}
class AutoFocusInput extends Component {
  componentDidMount () {
    this.input.focus()
  }

  render () {
    return (
      <input ref={(input) => this.input = input} />
    )
  }
}

ReactDOM.render(
  <AutoFocusInput />,
  document.getElementById('root')
)

给input 元素加了一个 ref 属性,这个属性值是一个函数。当 input 元素在页面上挂载完成以后,React.js 就会调用这个函数,并且把这个挂载以后的 DOM 节点传给这个函数。在函数中我们把这个 DOM 元素设置为组件实例的一个属性,这样以后我们就可以通过 this.input 获取到这个 DOM 元素。
注意:ref对应值是函数,函数以dom为参数;一般只用于普通html标签,不用于自定义组件上。

ReactDOM.render(
  <Card>
    <h2>React.js 小书</h2>
    <div>开源、免费、专业、简单</div>
    订阅:<input />
  </Card>,
  document.getElementById('root')
)
// Card组件
class Card extends Component {
  render () {
    return (
      <div className='card'>
        <div className='card-content'>
          {this.props.children}
        </div>
      </div>
    )
  }
}
  render () {
    return (
      <div
        className='editor-wrapper'       //这里用className,而不是class
        dangerouslySetInnerHTML={{__html: this.state.content}} /> //这个content不会转义
    )
  }

style的特殊性:1、接受一个对象,这个对象里面是这个元素的 CSS 属性键值对;2、原来 CSS 属性中带 - 的元素都必须要去掉 - 换成驼峰命名,如 font-size 换成 fontSize

<h1 style={{fontSize: '12px', color: this.state.color}}>React.js 小书</h1>
// npm install --save prop-types
import React, { Component } from 'react'
import PropTypes from 'prop-types'

class Comment extends Component {
  static propTypes = {
    comment: PropTypes.object.isRequired
  }

  render () {
    const { comment } = this.props
    return (
      <div className='comment'>
        <div className='comment-user'>
          <span>{comment.username} </span>:
        </div>
        <p>{comment.content}</p>
      </div>
    )
  }
}
//
PropTypes.array
PropTypes.bool
PropTypes.func
PropTypes.number
PropTypes.object
PropTypes.string
PropTypes.node
PropTypes.element
// 以Index里包含Header组件为例
class Index extends Component {
  static childContextTypes = {        // 1、声明state中属性类型,必须写
    themeColor: PropTypes.string
  }

  constructor () {
    super()
    this.state = { themeColor: 'red' }  //2、初始化state
  }

  getChildContext () {
    return { themeColor: this.state.themeColor }        //3、用state值生成后代可以共用的context
  }

  render () {
    return (
      <div>
        <Header />
      </div>
    )
  }
}

// 子组件是这样获取context的
class Header extends Component {
  static contextTypes = {        //只要声明contextTypes就可以通过this.context使用全局的context了
    themeColor: PropTypes.string
  }

  render () {
    return (
      <h1 style={{ color: this.context.themeColor }}>React.js 小书标题</h1>
    )
  }
}

参考

React.js 小书

上一篇 下一篇

猜你喜欢

热点阅读