React.js

函数是面向过程的,函数的调用不需要主体,而方法是属于对象的,调用方法需要一个主体-即对象。

npm install -g create-react-app
创建react项目(具体看react-commend) 项目名 描述 作者等配置可以全部默认
先创建文件夹 cd到目录下 create-react-app my-app(注意此处名字不能有大写)
然后 cd my-appnpm start启动

组件的state应该用来存储组件的事件处理函数随时可能会改变的数据,以达到重新渲染并保持组件的用户界面最新的目的

react事件触发,如onClick,onChange={this.fn.bind(this)}要用bind绑定事件以辨认

文末有贴士,也算是一种规范,习惯。

直接使用 BootCDN 的 React CDN 库,地址如下:




react.min.js - React 的核心库
react-dom.min.js - 提供与 DOM 相关的功能
babel.min.js - Babel 可以将 ES6 代码转为 ES5 代码,这样我们就能在目前不支持 ES6 浏览器上执行 React 代码。Babel 内嵌了对 JSX 的支持。通过将 Babel 和 babel-sublime 包(package)一同使用可以让源码的语法渲染上升到一个全新的水平。

ReactDOM.render(    /代码将一个 h1 标题,插入 id="example" 节点中。
    

Hello, world!

, document.getElementById('example') );

JSX语法

React 使用 JSX 来替代常规的 JavaScript。

  • JSX 是一个看起来很像 XML 的 JavaScript 语法扩展。
  • JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。
  • 它是类型安全的,在编译过程中就能发现错误。
    在 JSX 中使用 JavaScript 表达式。表达式写在花括号 {} 中
    在 JSX 中不能使用 if else 语句,但可以使用 conditional (三元运算) 表达式来替代。
ReactDOM.render(
    

{i == 1 ? 'True!' : 'False'}

, document.getElementById('example') );

JSX 允许在模板中插入数组,数组会自动展开所有成员:

var arr = [
  

菜鸟教程

,

学的不仅是技术,更是梦想!

, ]; ReactDOM.render(
{arr}
, document.getElementById('example') );

1、在标签内部的注释需要花括号
2、在标签外的的注释不能使用花括号

ReactDOM.render(
    /*注释 */
    

孙朝阳 {/*注释*/}

, document.getElementById('example') );

代码中嵌套多个 HTML 标签,需要使用一个标签元素包裹它

React 组件

var HelloMessage = React.createClass({
  render: function() {
    return 

Hello World!

; } }); ReactDOM.render( , document.getElementById('example') );

React.createClass 方法用于生成一个组件类 HelloMessage。
实例组件类并输出信息。
定义的 React 类名以大写字母开头,注意组件类只能包含一个顶层标签。

如果我们需要向组件传递参数,可以使用 this.props 对象:

var HelloMessage = React.createClass({
  render: function() {
    return 

Hello {this.props.name}

; } }); ReactDOM.render( , document.getElementById('example') );

class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。
可以通过创建多个组件来合成一个组件,即把组件的不同功能点进行分离。
组件名不一定是用单标签,也可以是双标签
==

React State(状态)

React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。

 var LikeButton = React.createClass({
        getInitialState: function() {
          return {liked: false};
        },
        handleClick: function(event) {
          this.setState({liked: !this.state.liked});
        },
        render: function() {
          var text = this.state.liked ? '喜欢' : '不喜欢';
          return (
            

{text}我。点我切换状态。

); } }); ReactDOM.render( , document.getElementById('example') );

与原生 HTML 不同,on 之后第一个字母是大写的。 onClick={this.handleClick}

React Props

state 和 props 主要的区别在于 props 是不可变的,而 state 可以根据与用户交互来改变。state 来更新和修改数据。 而子组件只能通过 props 来传递数据。
可以通过 getDefaultProps() 方法为 props 设置默认值:

var HelloMessage = React.createClass({
  getDefaultProps: function() {
    return {
      name: 'Runoob'
    };
  },
  render: function() {
    return 

Hello {this.props.name}

; } }); ReactDOM.render( , document.getElementById('example') );

可以在父组件中设置 state, 并通过在子组件上使用 props 将其传递到子组件上。

React 组件 API

setState(object nextState[, function callback])
合并nextState和当前state,并重新渲染组件。setState是React事件处理函数中和请求回调函数中触发UI更新的主要方法。setState()并不会立即改变this.state,而是创建一个即将处理的state。setState()并不一定是同步的,为了提升性能React会批量执行state和DOM渲染。setState()总是会触发一次组件重绘。

  • 设置状态:setState
  • 替换状态:replaceState
  • 设置属性:setProps
  • 替换属性:replaceProps
  • 强制更新:forceUpdate
  • 获取DOM节点:findDOMNode
  • 判断组件挂载状态:isMounted
var HelloMessage = React.createClass({
  getInitialState: function() {
    return {value: 'Hello Runoob!'};
  },
  handleChange: function(event) {
    this.setState({value: event.target.value});
  },
  render: function() {
    var value = this.state.value;
    return 

{value}

; } }); ReactDOM.render( , document.getElementById('example') );

React小书

组件化可以帮助我们解决前端结构的复用性问题,整个页面可以由这样的不同的组件组合、嵌套构成。组件的显示形态和行为可以由数据状态(state)和配置参数(props)共同决定。

编译阶段你需要借助 Babel;需要 Redux 等第三方的状态管理工具来组织代码;如果你要写单页面应用那么你需要 React-router。这就是所谓的“React.js全家桶”。

一个 DOM 元素包含的信息其实只有三个:标签名,属性,子元素。
JSX 在编译的时候会变成相应的 JavaScript 对象描述。
我们在编写 React.js 组件的时候,一般都需要继承 React.js 的 Component(还有别的编写组件的方式我们后续会提到)。一个组件类必须要实现一个 render 方法,这个 render 方法必须要返回一个 JSX 元素。但这里要注意的是,必须要用一个外层的 JSX 元素把所有内容包裹起来。返回并列多个 JSX 元素是不合法的,下面是错误的做法:

render () {
  return (
    
第一个
第二个
) }

正确写法:

render () {
  return (
    
第一个
第二个
) }

{} 内可以放任何 JavaScript 的代码,包括变量、表达式计算、函数执行等等。 render 会把这些代码返回的内容如实地渲染到页面上,非常的灵活。
表达式插入不仅仅可以用在标签内部,也可以用在标签的属性上。
JSX 元素其实可以像 JavaScript 对象那样自由地赋值给变量,或者作为函数参数传递、或者作为函数的返回值。
作为变量:

const isGoodWord = true
const goodWord =  is good
const badWord =  is not good
  {isGoodWord ? goodWord : badWord}
// 作为函数:
renderGoodWord (goodWord, badWord) {
  const isGoodWord = true
  return isGoodWord ? goodWord : badWord
}        // 伪代码
{this.renderGoodWord(
           is good,
           is not good
)}

自定义的组件都必须要用大写字母开头,普通的 HTML 标签都用小写字母开头。

class Index extends Component {
  render () {
    return (
      
)}} ReactDOM.render( , document.getElementById('root') ) //组件间的嵌套 树状结构

React.js 监听事件

只需要给需要监听事件的元素加上属性类似于 onClick、onKeyDown 这样的属性。
React.js 帮我们封装好了一系列的 on* 的属性,当你需要为某个元素监听某个事件的时候,只需要简单地给它加上 on* 就可以了。这些事件属性名都必须要用驼峰命名法。

这些 on* 的事件监听只能用在普通的 HTML 的标签上,而不能用在组件标签上。也就是说,

这样的写法不会有什么效果的。

事件监听函数会被自动传入一个 event 对象,event 对象并不是浏览器提供的,而是它自己内部所构建的。

class Title extends Component {
  handleClickOnTitle (e) {
    console.log(e.target.innerHTML) }
  render () {
    return (
      

React 小书

) } }
关于事件中的 this

React.js 调用你所传给它的方法的时候,并不是通过对象方法的方式调用(this.handleClickOnTitle),而是直接通过函数调用 (handleClickOnTitle),所以事件监听函数内并不能通过 this 获取到实例。如果你想在事件函数当中使用当前的实例,你需要手动地将实例方法 bind 到当前实例上再传入给 React.js。bind 会把实例方法绑定到当前实例上,然后我们再把绑定后的函数传给 React.js 的 onClick 事件监听。

bind 不仅可以帮我们把事件监听方法中的 this 绑定到当前组件实例上;还可以帮助我们在在渲染列表元素的时候,把列表元素传入事件监听函数当中,后面会介绍。

class LikeButton extends Component {
  constructor () {
    super()
    this.state = { isLiked: false }  //  这个对象在构造函数里面初始化  
  }
  handleClickOnLikeButton () {
    this.setState({  //  setState 函数,每次点击都会更新 isLiked 属性
      isLiked: !this.state.isLiked    })
  }
}

setState 方法由父类 Component 所提供。
React.js 内部会把 JavaScript 事件循环中的消息队列的同一个消息中的 setState 都进行合并以后再重新渲染组件。所以并不需要担心多次进行 setState 会带来性能问题。

组件内部是通过 this.props 的方式获取到组件的参数的,如果 this.props 里面有需要的属性我们就采用相应的属性,没有的话就用默认的属性。

在使用一个组件的时候,可以把参数放在标签的属性当中,所有的属性都会作为 props 对象的键值:

class Index extends Component {
  render () {
    return (
      
) } }

前面的章节我们说过,JSX 的表达式插入可以在标签属性上使用。所以其实可以把任何类型的数据作为组件的参数,包括字符串、数字、对象、数组、甚至是函数等等:

JSX 的 {} 内可以嵌入任何表达式,{{}} 就是在 {} 内部用对象字面量返回一个对象而已。

  static defaultProps = {  //如果没有传进来,会直接使用 defaultProps 中的默认属性。
    likedText: '取消',
    unlikedText: '点赞'
  }   //defaultProps 作为点赞按钮组件的类属性,里面是对 props 中各个属性的默认配置。

state 是让组件控制自己的状态,props 是让外部对组件自己进行配置。尽量少地用 state,尽量多地用 props。因为状态会带来管理的复杂性,我们尽量多地写无状态组件,尽量少地写有状态的组件。这样会降低代码维护的难度,也会在一定程度上增强组件的可复用性。

渲染列表数据

一般来说,在 React.js 处理列表就是用 map 来处理、渲染的。
{ users.map((user) => ) }
对于用表达式套数组罗列到页面上的元素,都要为每个元素加上 key 属性,这个 key 必须是每个元素唯一的标识。一般来说,key 的值可以直接后台数据返回的 id,因为后台的 id 都是唯一的。

{ users.map((user, i) => )}
在实际项目当中,如果你的数据顺序可能发生变化,标准做法是最好是后台数据返回的 id 作为列表元素的 key。

React.js生命周期

React.js 将组件渲染,并且构造 DOM 元素然后塞入页面的过程称为组件的挂载(这个定义请好好记住)。

挂载阶段

React.js 会在组件的 render 之前调用 componentWillMount,在 DOM 元素塞入页面以后调用 componentDidMount。而componentWillUnmount控制了这个组件的删除过程。

-> constructor()
-> componentWillMount()
-> render()
// 然后构造 DOM 元素插入页面
-> componentDidMount()
// ...
// 即将从页面中删除
-> componentWillUnmount()
// 从页面中删除

我们一般会把组件的 state 的初始化工作放在 constructor 里面去做;
在 componentWillMount 进行组件的启动工作,例如 Ajax 数据拉取、定时器的启动;组件从页面上销毁的时候,有时候需要一些数据的清理,例如定时器的清理,就会放在 componentWillUnmount 里面去做。如下:

  constructor () {
    super()
    this.state = {
      date: new Date()
    }
  }
每隔 1 秒更新中的 state.date,这样页面就可以动起来了。
  componentWillMount () {
    this.timer = setInterval(() => {
      this.setState({ date: new Date() })
    }, 1000)
  }

现页面上有个按钮可显示或者隐藏时钟,当时钟隐藏的时候,我们并没有清除定时器。
添加 componentWillUnmount,在组件销毁的时候清除该组件的定时器:

  componentWillUnmount () {
    clearInterval(this.timer)
  }
更新阶段(说白了就是 setState,先了解即可)

shouldComponentUpdate(nextProps, nextState):你可以通过这个方法控制组件是否重新渲染。如果返回 false 组件就不会重新渲染。这个生命周期在 React.js 性能优化上非常有用。
componentWillReceiveProps(nextProps):组件从父组件接收到新的 props 之前调用。
componentWillUpdate():组件开始重新渲染之前调用。
componentDidUpdate():组件重新渲染并且把更改变更到真实的 DOM 以后调用。

ref属性

React.js 当中提供了 ref 属性来帮助我们获取已经挂载的元素的 DOM 节点,你可以给某个 JSX 元素加上 ref属性:

  componentDidMount () {
    this.input.focus()
  }
  render () {
    return (
       this.input = input} />
    )  }
}   //我们就可以通过 this.input 获取到这个 DOM 元素。
就可以在 componentDidMount 中使用这个 DOM 元素。并且调用 this.input.focus() 的 DOM API。

但是记住一个原则:能不用 ref 就不用。不利于我们理解和维护。
其实可以给组件标签也加上 ref ,例如:
this.clock = clock} />

props.children

组件本身是一个不带任何内容的方形的容器,可以在用这组件的时候给它传入任意内容
嵌套的结构在组件内部都可以通过 props.children 获取到,这种组件编写方式在编写容器类型的组件当中非常有用。而在实际的 React.js 项目当中,我们几乎每天都需要用这种方式来编写组件。
http://huziketang.com/books/react/lesson22
{this.props.children}
React.js 就是把我们嵌套的 JSX 元素一个个都放到数组当中,然后通过 props.children 传给了Card

dangerouslySetHTML 和 style 属性
  render () {
    return (
      
) }

需要给 dangerouslySetInnerHTML 传入一个对象,这个对象的 __html 属性值就相当于元素的 innerHTML,这样我们就可以动态渲染元素的 innerHTML 结构了。因为设置 innerHTML 可能会导致跨站脚本攻击(XSS).这个属性不必要的情况就不要使用。

style 接受一个对象,这个对象里面是这个元素的 CSS 属性键值对,原来 CSS 属性中带 - 的元素都必须要去掉 - 换成驼峰命名,如 font-size 换成 fontSize,text-align 换成 textAlign。我们用 setState 就可以修改样式。

React.js 小书


只要简单地 setState({color: 'blue'}) 就可以修改元素的颜色成蓝色。

React 提供的第三方库 prop-types

通过 PropTypes 给组件的参数做类型限制,这在构建大型应用程序的时候特别有用。
npm install --save prop-types
http://huziketang.com/books/react/lesson24
在文件头部引入了 PropTypes import PropTypes from 'prop-types'
并且给 Comment 组件类添加了类属性 propTypes,里面的内容的意思就是你传入的 comment 类型必须为 object(对象)。isRequired 关键字来强制组件某个参数必须传入.:

static propTypes = {
  comment: PropTypes.object.isRequired
}

贴士

组件的私有方法都用 _ 开头,所有事件监听的方法都用 handle 开头。把事件监听方法传给组件的时候,属性名用 on 开头。监听(on)CommentInput 的 Submit 事件,并且交给 this 去处理(handle)。这样思路非常清晰。

组件的内容编写顺序如下:

  1. static 开头的类属性,如 defaultProps、propTypes。
  2. 构造函数,constructor。
  3. getter/setter(还不了解的同学可以暂时忽略)。
  4. 组件生命周期。
  5. _ 开头的私有方法。
  6. 事件监听方法,handle*。
  7. render开头的方法,有时候 render() 方法里面的内容会分开到不同函数里面进行,这些函数都以 render 开头。
  8. render() 方法。

React ES5 与 ES6 区别

React Router

npm install -S react-router
使用时,路由器Router就是React的一个组件。

import { Router } from 'react-router';
render(, document.getElementById('app'));

Router组件本身只是一个容器,真正的路由要通过Route组件定义。

import { Router, Route, hashHistory } from 'react-router';
render((
  
    
  
), document.getElementById('app'));

用户访问根路由/(比如http://www.example.com/),组件APP就会加载到document.getElementById('app')。Router组件有一个参数history,它的值hashHistory表示,路由的切换由URL的hash变化决定,即URL的#部分发生变化。举例来说,用户访问http://www.example.com/,实际会看到的是http://www.example.com/#/。

Route组件定义了URL路径与组件的对应关系。你可以同时使用多个Route组件。


  
  
  

上面代码中,用户访问/repos(比如http://localhost:8080/#/repos)时,加载Repos组件;访问/about(http://localhost:8080/#/about)时,加载About组件。

嵌套路由


  
    
    
  

上面代码,用户访问/repos时,会先加载App组件,然后在它的内部再加载Repos组件。


  

this.props.children属性就是子组件。

path 属性

Route组件的path属性指定路由的匹配规则。这个属性是可以省略的,这样的话,不管路径是否匹配,总是会加载指定组件。


   

当用户访问 /inbox/messages/:id 时,会加载下面的组件。


  

如果省略外层Route的path参数,写成下面的样子。


  

现在用户访问 /inbox/messages/:id 时,组件加载还是原来的样子。

path属性可以使用通配符。


// 匹配 /hello/michael
// 匹配 /hello/ryan


// 匹配 /hello
// 匹配 /hello/michael
// 匹配 /hello/ryan


// 匹配 /files/hello.jpg
// 匹配 /files/hello.html


// 匹配 /files/ 
// 匹配 /files/a
// 匹配 /files/a/b


// 匹配 /files/hello.jpg
// 匹配 /files/path/to/file.jpg

通配符的规则如下。
(1):paramName
:paramName匹配URL的一个部分,直到遇到下一个/、?、#为止。这个路径参数可以通过this.props.params.paramName取出。
(2)()
()表示URL的这个部分是可选的。
(3)*
*匹配任意字符,直到模式里面的下一个字符为止。匹配方式是非贪婪模式。
(4) **
** 匹配任意字符,直到下一个/、?、#为止。匹配方式是贪婪模式。

路由匹配规则是从上到下执行,一旦发现匹配,就不再其余的规则了。

设置路径参数时,需要特别小心这一点。


  
  

IndexRoute 组件

显式指定Home是根路由的子组件,即指定默认情况下加载的子组件。你可以把IndexRoute想象成某个路径的index.html。


  
    
    
    
  

用户访问 / 的时候,加载的组件结构如下。


  

App只包含下级组件的共有元素,本身的展示内容则由Home组件定义。这样有利于代码分离,也有利于使用React Router提供的各种API。

Redirect 组件

组件用于路由的跳转,即用户访问一个路由,会自动跳转到另一个路由。


  {/* 从 /inbox/messages/:id 跳转到 /messages/:id */}
  

现在访问 /inbox/messages/5,会自动跳转到/messages/5。

IndexRedirect组件用于访问根路由的时候,将用户重定向到某个子组件。


  <IndexRedirect to="/welcome" />
  
  

用户访问根路径时,将自动重定向到子组件welcome。

Link

Link组件用于取代元素,生成一个链接,允许用户点击后跳转到另一个路由。它基本上就是元素的React 版本,可以接收Router的状态。

render() {
  return 
  • About
  • Repos
}

如果链接到根路由/,不要使用Link组件,而要使用IndexLink组件。

histroy 属性

Router组件的history属性,用来监听浏览器地址栏的变化,并将URL解析成一个地址对象,供 React Router 匹配。
history属性,一共可以设置三种值。

  • browserHistory
  • hashHistory
  • createMemoryHistory

如果设为hashHistory,路由将通过URL的hash部分(#)切换,URL的形式类似example.com/#/some/path

如果设为browserHistory,浏览器的路由就不再通过Hash完成了,而显示正常的路径example.com/some/path 但是,这种情况需要对[服务器改造])。

你可能感兴趣的:(React.js)