生命周期
按顺序
组件实例被创建和插入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内部实现机制吗?