react

545 阅读5分钟

生命周期

按顺序

组件实例被创建和插入DOM中时被调用
constructor()              构造
componentWillMount()       组件将要挂载
render()                   渲染
componentDidMount()        挂载完成 dom操作

在父组件里面改变props传值的时候触发的
componentWillReceiveProps

组件数据更新的时候触发的生命周期函数
shouldComponentUpdate       是否要更新数据 return ture
componentWillUpdate         组件将要更新    
render            
componentDidUpdate          组件更新

销毁-当一个组件被从DOM中移除时
componentWillUnmount()

介绍

React 不是一个 MVC 框架,仅仅是视图(V)层的库
通过 diff算法 和 虚拟DOM 实现视图的高效更新
记录两棵DOM树差异

npm i -S react react-dom
react:react 是React库的入口点
react-dom:提供了针对DOM的方法,比如:把创建的虚拟DOM,渲染到页面上

ReactDOM.render(divVD, document.getElementById('app')).
// 参数
虚拟dom对象;
dom对象表示渲染到哪个元素内;
回调函数

创建虚拟DOM JSX

// 参数
元素名称;
元素属性对象(null表示无) ;
当前元素的子元素string||createElement() 的返回值
const divVD = React.createElement('div', {
  title: 'hello react'
}, 'Hello React!!!')


JSX语法,最终会被编译为 createElement() 方法

如果在 JSX 中给元素添加类, 需要使用 className 代替 class
类似:label 的 for属性,使用htmlFor代替
注意 2:在 JSX 中可以直接使用 JS代码,直接在 JSX 中通过 {} 中间写 JS代码即可
注意 3:在 JSX 中只能使用表达式,但是不能出现 语句!!!
注意 4:在 JSX 中注释语法:{/* 中间是注释的内容 */}

创建组件

1 通过 JS函数 创建(无状态组件)

  只有render方法,使用function构造函数创建组件
  以 props 为参数的 function 返回 JSX 元素就搞定了
 
 注意: 
    大写字母开头,
    数必须有返回值,JSX对象或null
    返回的JSX,必须有一个根元素
    组件的返回值使用()包裹,避免换行问题
  
  function Square(props) {
    // 注释
      return (
        {/* 此处 注释要{}包裹 */}
        <button className="square" onClick={props.onClick}>
          {props.value}
        </button>
      );
}

2 通过 class 创建(有状态组件)

使用`constructor`构造函数,创建实例属性
rander方法 且显示return一个react对象或者null

class Square extends React.Component {
  render() {
    constructor() {
     // 必须调用super(), super表示父类的构造函数
        super()
        this.state = {
          xIsNext: true,
          stepNumber: 0
        }
     }
  
    return (
      <button className="square" onClick={() => this.props.onClick()}>
        {this.state.stepNumber}
      </button>
    )
  }
}


变化

所有的 this.props 替换成参数 props. 
 onClick={() => this.props.onClick()} 直接修改为 onClick={props.onClick} 
 注意不能写成 onClick={props.onClick()} 否则 props.onClick 方法
 会在 Square 组件渲染时被直接触发
 而不是等到 Board 组件渲染完成时通过点击触发,
 又因为此时 Board 组件正在渲染中(即 Board 组件的 render() 方法正在调用),
 又触发 handleClick(i) 方法调用 setState() 会再次调用 render() 方法导致死循环。
 
 key属性在React内部使用,但不会传递给你的组件
推荐:在遍历数据时,推荐在组件中使用 key 属性
注意:key只需要保持与他的兄弟节点唯一即可,不需要全局唯一
注意:尽可能的减少数组index作为key,数组中插入元素的等操作时,会使得效率底下

组件传参和类型检查

传参(只读的props)
可以把父组件传过去hello={this}
父
<Hello username="zx" age={20} hello={this} />
getChildData = result => {
    alert(result)
}
子
<button onClick={this.props.hello.getChildData.
bind(this,'我是子组件的数据')}>子组件给父组件传值</button>

父组件主动获取子组件的数据
    1、调用子组件的时候指定ref的值 <Header ref='header'></Header>
    2、通过this.refs.header  数据或方法
    获取整个子组件实例(dom(组件)加载完成以后获取 )
    
import PropTypes from 'prop-types';
类.propTypes={
    num:PropTypes.number
}

//defaultProps   
如果父组件调用子组件的时候不给子组件传值,
可以在子组件中使用defaultProps定义的默认值
Header.defaultProps={
    title:'标题'
}

组件状态


用来给组件提供组件内部使用的数据
只有通过class创建的组件才具有状态
状态是私有的,完全由组件来控制
**不要在 state 中添加 render() 方法中不需要的数据,会影响渲染性能!**
可以将组件内部使用但是不渲染在视图中的内容,直接添加给 this

样式style

// 1. 直接写行内样式:
<li style={{border:'1px solid red', fontSize:'12px'}}></li>

// 2. 抽离为对象形式
var styleH3 = {color:'blue'}
var styleObj = {
  liStyle:{border:'1px solid red', fontSize:'12px'},
  h3Style:{color:'green'}
}

<li style={styleObj.liStyle}>
  <h3 style={styleObj.h3Style}>评论内容:{props.content}</h3>
</li>

// 3. 使用样式表定义样式:
import '../css/comment.css'
<p className="pUser">评论人:{props.user}</p>

事件this

谨慎对待 JSX 回调函数中的 this,类的方法默认是不会绑定 this 的。
如果你忘记绑定 this.handleClick 并把它传入 onClick, 
当你调用这个函数的时候 this 的值会是 undefined。
将事件处理函数运行时的 this 指向当前组件实例。

1.  使用属性初始化器来正确的绑定回调函数
      <input
        type="text"
        value={this.state.newText}
        onChange={this.handleChange}
      />
      
    handleChange = e => {}
    
2. 在回调函数中使用 箭头函数
   参数显示的传递
   // onChange={this.handleChange.bind(this)}
    <input
        type="text"
        value={this.state.newText}
        onChange={(e) => this.handleChange(e)}
      />
      
      handleChange(e) {}
3. 构造函数中bind
   参数可以隐式传递
   this.handleChange = this.handleChange.bind(this)

元素渲染

// 图片
import logo from '../assets/images/1.jpg'
<img src={logo} />
<img src={require('../assets/images/1.jpg')} />

// 列表     
list2: [<h2 key="1">我是一个h2</h2>, <h2 key="2">我是一个h2</h2>],
{this.state.list2}
let listResult = this.state.list.map(function(value, key) {
      return <li key={key}>{value}</li>
    })
<ul>{listResult}</ul>

// 表达式
const status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
不加括号有问题

// 表单
<input type="radio" value="1" 
checked={this.state.sex==1}  onChange={this.handelSex}/>

{
    // 注意this指向
    this.state.hobby.map((value,key)=>{
        return (
           <span key={key}>
            <input type="checkbox"  checked={value.checked}  onChange={this.handelHobby.bind(this,key)}/> {value.title} 
           </span>
        )
    })
}
// 事件
event.target.style.background="red"
alert( event.target.getAttribute('id'))
onKeyDown e.keyCode

react-router-dom

<Link>to字符串或者location对象(包含pathname,search,hash与state属性)
<Link to={{ pathname: '/roster/7' }}>Player #7</Link>

动态路由
配置:<Route path="/content/:aid" component={Content} />   
获取:this.props.match.params
跳转:<Link to={`/content/${value.aid}`}>{value.title}</Link>

react get传值 
1、获取 this.props.location.search

axios

jsonp不太友好,推荐用CORS方式(后端运行跨域)
axios
  .get(api)
  .then(response => {
    console.log(response)
  })
  .catch(function(error) {
    console.log(error)
  })
  

其他

fetchJsonp('/users.jsonp')
.then(function(response) {
  return response.json()
}).then(function(json) {
  console.log('parsed json', json)
}).catch(function(ex) {
  console.log('parsing failed', ex)
})
    
    
.slice() 方法来将之前的数组数据浅拷贝到新数组
state会重渲染

todo

React中的controlled component 和 uncontrolled component区别(受控组件和不受控组件)。 了解过react-router内部实现机制吗?