一. React的基本使用
API
- ReactDOM.render(vDom, dDom) // 挂载组件,第一个参数为虚拟dom节点,第二个参数为要挂载的真实dom
- ReactDOM.unmountComponentAtNode(dDom) // 卸载dom下的组件
-
React.createElement(tag, props, node) // 创建虚拟dom,第一个参数为标签名,第二个参数名为属性值,第三个参数为文本内容
const msg = 'i like you!' const myId = 'atguigu' const vDom1 = React.createElement('h2', { id: myId.toLowerCase(), className: myId.toLowerCase() }, msg.toLowerCase())
1.1 相关js库
- react.js:React核心库。
- react-dom.js:提供操作DOM的react扩展库。
- babel.min.js:解析JSX语法代码转为JS代码的库。
1.2 hello,react
<!-- 准备好一个“容器” -->
<div id="test"></div>
<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- 引入react-dom,用于支持react操作DOM -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!-- 引入babel,用于将jsx转为js -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel" > /* 此处一定要写babel */
// 1.创建虚拟DOM
const VDOM = <h1>Hello,React</h1> /* 此处一定不要写引号,因为不是字符串 */
// 2.渲染虚拟DOM到页面
ReactDOM.render(VDOM, document.getElementById('test'))
</script>
1.3 JSX(JavaScript XML)
react 定义的一种类似于XML的JS扩展语法: JS + XML 本质是React.createElement(component, props, …children)方法的语法糖 (标签名, 属性, 文本内容)
1.3.1 作用
用来简化创建虚拟DOM
注意点:
- 不是字符串, 也不是HTML/XML标签
- 最终产生的就是一个JS对象
语法规则:
- 遇到 < 开头的代码, 以标签的语法解析: html同名标签转换为html同名元素, 其它标签需要特别解析
- 遇到以 { 开头的代码,以JS语法解析: 标签中的js表达式必须用{ }包含
1.3.2 渲染虚拟DOM(元素)
- 语法: ReactDOM.render(virtualDOM, containerDOM)
- 作用: 将虚拟DOM元素渲染到页面中的真实容器DOM中显示
- 参数说明
1)参数一: 纯js或jsx创建的虚拟dom对象
2)参数二: 用来包含虚拟DOM元素的真实dom元素对象(一般是一个div)
<div id="test1"></div>
<div id="test2"></div>
<script src="./js/react.development.js"></script>
<script src="./js/react-dom.development.js"></script>
<script src="./js/babel.min.js"></script>
<script>
const msg = 'i like you!'
const myId = 'atguigu'
const vDom1 = React.createElement('h2', { id: myId.toLowerCase(), className: myId.toLowerCase() }, msg.toLowerCase())
ReactDOM.render(vDom1, document.getElementById('test1'))
</script>
<script type="text/babel">
const vDom2 = <h3 id={ myId.toUpperCase() }>{ msg.toUpperCase() }</h3>
ReactDOM.render(vDom2, document.getElementById('test2'))
</script>
渲染结果
1.3.3 遍历列表小练习
<script type="text/babel">
const names = ['react', 'vue', 'jQuery']
const vDom = (
<ul>
{ names.map((item, index) => <li key={index}>{ item }</li>) }
</ul>
)
ReactDOM.render(vDom, document.getElementById('test1'))
</script>
二. 组件化
2.1 简单例子
<script type="text/babel">
/**
* 方式一:工厂函数组件
*/
function MyComponent1() {
return <h1>工厂函数组件</h1>
}
/**
* 方式二:类组件
*/
class MyComponent2 extends React.Component {
render() {
return <h1>类组件</h1>
}
}
ReactDOM.render(<MyComponent1 />, document.getElementById('test1'))
ReactDOM.render(<MyComponent2 />, document.getElementById('test2'))
</script>
2.2 组件三大属性
2.2.1 state
- state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
- 组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)
<script type="text/babel">
class Like extends React.Component {
constructor (props) {
super(props)
// 初始化状态
this.state = {
isLikeMe: false
}
// 修改this指向
this.handleClick = this.handleClick.bind(this)
}
// 新添加的方法内部this为undefined
handleClick () {
// 获取状态并取反
const isLikeMe = !this.state.isLikeMe
// 更新状态
this.setState({ isLikeMe })
}
render() {
const { isLikeMe } = this.state
return <h1 onClick={ this.handleClick }>{ isLikeMe ? '你喜欢我' : '我喜欢你' }</h1>
}
}
ReactDOM.render(<Like />, document.getElementById('test1'))
</script>
注意:
- 组件中render方法中的this为组件实例对象
- 组件自定义的方法中this为undefined,如何解决?
a)强制绑定this: 通过函数对象的bind()
b)箭头函数 - 状态数据,不能直接修改或更新
2.2.2 props
通过标签属性从组件外向组件内传递变化的数据
注意: 组件内部不要修改props数据
编码操作:
-
内部读取某个属性值
this.props.name
-
对props中的属性值进行类型限制和必要性限制
第一种方式(React v15.5 开始已弃用):Person.propTypes = { name: React.PropTypes.string.isRequired, age: React.PropTypes.number }
第二种方式(新):使用prop-types库进限制(需要引入prop-types库)
Person.propTypes = { name: PropTypes.string.isRequired, // 必填,string 类型 age: PropTypes.number. }
-
默认 Prop 值
Person.defaultProps = { age: 18, sex:'男' }
工厂函数构建
<script type="text/babel">
function Person(props) {
return (
<ul>
<li>姓名:{ props.name }</li>
<li>年龄:{ props.age }</li>
<li>性别:{ props.sex }</li>
</ul>
)
}
const p1 = {
name: '张三'
}
// 默认值
Person.defaultProps = {
age: 18,
sex: '男'
}
// 限制类型
Person.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number
}
ReactDOM.render(<Person name={ p1.name } />, document.getElementById('test1'))
</script>
组件类构建
<script type="text/babel">
class Person extends React.Component {
render() {
return (
<ul>
<li>姓名:{this.props.name}</li>
<li>年龄:{this.props.age}</li>
<li>性别:{this.props.sex}</li>
</ul>
)
}
}
const p1 = {
name: '李四',
age: 20
}
// 默认值
Person.defaultProps = {
age: 18,
sex: '男'
}
// 限制类型
Person.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number
}
ReactDOM.render(<Person { ...p1 } />, document.getElementById('test1'))
</script>
2.2.3 refs
组件内的标签可以定义ref属性来标识自己
- 字符串形式的ref
<input ref="input1" /> // 通过 refs 获取dom const input1 = this.refs.input1
- 回调形式的ref
<input ref={ c => this.input1 = c } /> // 通过 this.xxx 获取dom console.log(this.input1.value)
- createRef 创建 ref 容器(新版本)
class CustomTextInput extends React.Component { constructor(props) { super(props) // 创建一个 ref 来存储 textInput 的 DOM 元素 this.textInput = React.createRef() this.focusTextInput = this.focusTextInput.bind(this) } focusTextInput() { // 注意:我们通过 "current" 来访问 DOM 节点 this.textInput.current.focus() } render() { // 告诉 React 我们想把 <input> ref 关联到 // 构造器里创建的 `textInput` 上 return ( <div> <input type="text" ref={ this.textInput } /> <input type="button" onClick={ this.focusTextInput } /> </div> ) } }
2.2.4 组件化简单demo
<script type="text/babel">
class App extends React.Component {
constructor(props){
super(props)
this.state = {
todos: ['吃饭', '睡觉', '打豆豆']
}
this.addTodo = this.addTodo.bind(this)
}
addTodo(res) {
const { todos } = this.state
todos.unshift(res)
this.setState({ todos })
}
render() {
const { todos } = this.state
return (
<div>
<Add count={ todos.length } addTodo={ this.addTodo } />
<List todos={ todos } />
</div>
)
}
}
class Add extends React.Component {
constructor(props){
super(props)
this.input = React.createRef()
this.add = this.add.bind(this)
}
add () {
const inputValue = this.input.current.value.trim()
if (inputValue) {
this.props.addTodo(inputValue)
this.input.current.value = ''
}
}
render() {
return (
<div>
<input type="text" ref={ this.input } />
<button onClick={ this.add }>#{ this.props.count + 1 }</button>
</div>
)
}
}
Add.propTypes = {
count: PropTypes.number.isRequired,
addTodo: PropTypes.func.isRequired
}
class List extends React.Component {
constructor(props){
super(props)
}
render() {
const { todos } = this.props
return (
<ul>
{ todos.map((item, index) => <li key={ index }>{ item }</li>) }
</ul>
)
}
}
List.propTypes = {
todos: PropTypes.array.isRequired,
}
ReactDOM.render(<App />, document.getElementById('test1'))
</script>
三. 生命周期
- 初始化阶段: 由ReactDOM.render()触发—初次渲染
1.constructor()
2.componentWillMount() // 组件挂载完成前
3.render() // 初始化渲染或更新渲染调用
4.componentDidMount() // 组件挂载完成后,开启监听, 发送ajax请求 - 更新阶段: 由组件内部this.setSate()或父组件重新render触发
1.componentWillUpdate() // 数据更新前
2.componentDidUpdate() // 数据更新后 - 销毁阶段: 由**ReactDOM.unmountComponentAtNode()**触发
1.componentWillUnmount() // 组件销毁前,做一些收尾工作, 如: 清理定时器