第一个React程序
函数式组件
//引入react核心
import React from 'react'
//引入react对dom操作的核心,相对于react-native而言的
import ReactDOM from 'react-dom'
//定义一个函数式组件
const app=(props)=><h1>还原进入{props.name}的世界</h1>
//点用渲染方法
ReactDOM.render(
<App name="react" />, //第一个参数为el组件
document.getElementById('root') // 第二个参数为dom根节点
)
class组件
//引入react核心
import React from 'react'
//引入react对dom操作的核心,相对于react-native而言的
import ReactDOM from 'react-dom'
//定义一个class组件
class App extends React.Component {
render(){
return(
<h1>还原进入{this.props.name}的世界</h1>
)
}
}
//点用渲染方法
ReactDOM.render(
<App name="react" />, //第一个参数为el组件
document.getElementById('root') // 第二个参数为dom根节点
)
组件的组合和嵌套
将一个组件渲染到另一个组件内部构成父子组件关系
注:react组件不存在vue那样的slot内容分发机制
//引入react核心
import React,{Component,Fragment } from 'react'
//引入react对dom操作的核心,相对于react-native而言的
import ReactDOM from 'react-dom'
class Title extends Component {
render(){
return(
<h1>还原进入{this.props.name}的世界</h1>
)
}
}
class Content extends Component {
render(){
return(
<p>{this.props.name}是世界上最好的框架(vue听到想打人)</p>
)
}
}
//定义一个class组件
class App extends Component {
render(){
return(
<Fragment> //类似vue的template节点
<Title name='react'/>
<Content name='react'/>
</Fragment>
)
}
}
//点用渲染方法
ReactDOM.render(
<App name="react" />, //第一个参数为el组件
document.getElementById('root') // 第二个参数为dom根节点
)
JSX原理
将js和html融合在一起的一种写法,浏览器无法直接识别,最终需要编译成js语言
**行内样式
//这里有两个大括号,第一个大括号表示需要在JSX中插入JS,第二个括号是用对象的形//式表达样式
<p style={{color:'red',fontSize:'14px'}}>Hello World</p>
**class
<p class='hello'>Hello World</p>
使用classNames包
npm install classnames
class Button extends React.Component {
// ...
render () {
var btnClass = 'btn';
if (this.state.isPressed) btnClass += ' btn-pressed';
else if (this.state.isHovered) btnClass += ' btn-over';
return <button className={btnClass}>{this.props.label}</button>;
}
}
组件的数据挂载
props (属性)
props是属性的意思,用来描述当前组件的特征,一般用于外界传入,如函数式组件的参数传入,或者class组件的构造函数传入。一般不能在内部更改。
**设置组件的默认props
class组件===》在class内部使用静态属性 static defaultProps = {name:'react'}
函数式组件===》挂载在函数上的属性(非原型属性)func.defaultProps={name:'react'}
**props.children
props.children相当于一个嵌套内容的占位符,运训在组件标签之间嵌套内容
const App = (props) = >{
return(
<p>{props.children}</p>
)
}
state(状态)
状态是组件内部使用的数据,组件自己维护
class App extends Component{
constructor(){
super()
//定义state
this.state = {
name:'react',
isLink;false
}
}
handleClick=()=>{
//不能直接给state赋值,因为没有被跟踪,必须使用setState进行响应式绑定
this.setState({
isLink:!this.state.isLink
})
}
render(){
return(
<div>
<h1>hello to {this.state.name} world</h1>
<button onClick={this.handleClick}>
{this.state.isLink?'取消':'收藏'}
</<button>>
</div>
)
}
}
完整的setState方法,第一个函数的参数中可以拿到当前state和props
this.setState((prevState,props)=>{
return {
isLink:!prevState.isLink
}
},()=>{
//这个回调可以获取最新的state值
})
渲染数据
**条件渲染
{
condition?‘取消’:‘收藏’
}
**列表渲染
const people = [
{
id:1,
name:'a'},
{
id:2,
name:'b'},
{
id:3,
name:'c'},
]
people.map((item)=>{
return(
<span>id:{item.id}</span>
<div>name:{item.name}</div>
)
})
dangerrouslySetHTML(富文本)
content='<p>xxxx</p>'
render(){
return(
<div dangerouslySetHTML={{__html:this.state.content}}></div>
)
}
事件处理
绑定事件
采用on+事件名的方式来绑定一个事件,注意,这里和原生的事件是有区别的,原生的事件全是小写onclick, React里的事件是驼峰onClick,React的事件并不是原生事件,而是合成事件。
**handler的写法:
在组件内使用箭头函数定义一个方法(推荐)
handleInputChange = (e) => {
this.setState({
[e.target.name]: e.target.value
})
}
render(){
<input
type="text"
name="xing"
value={xing}
onChange={this.handleInputChange}
/>
}
组件的生命周期
初始化
1,constructor(props)
constructor(props){
//用来绑定props,后面就可以用this.props调用
super(props)
//可初始化state,构造函数中不要使用setState()更新状态
this.state={
//可用props初始化内容
name:props.name
}
}
2,static getDerivedStateFromProps(nextProps,prevState)
组件实例化之后,父组件传递新的props的时候会触发
3,componentWillMount()
在render前调用,不建议使用
4,render()
当render方法被调用后,其返回一个可供后续渲染成真正DOM的类型
5,componentDidMount()
当组件真正被渲染成真实DOM后触发,此处才可以进行DOM操作,如加载第三方DOM库或者手动更改DOM等
更新
1,componentWillRecevieProps()
在挂载后,如果props有改变,则会触发
官方推荐getDerivedStateFromProps
2,static getDerivedStateFromProps()
同上
3,shouldComponentUpdate(nextProps, nextState)
可以获取将变更的参数
如果返回false,则4,5,6不会被触发
4,componentWillUpdate()
render前调用,不推荐
5,render()
同上
6,getSnapshotBeforeUpdate()
在render输出但为最终渲染前调用
能够获取DOM的当前状态,如滚动条更新前的高度
这个勾子返回的任何值都将传递给componentDidUpdate()
7,compontentDidUpdate(prevProps,prevState,snapshot)
销毁
1,componentWillUnmount()
组件销毁前触发,可执行一些必要的清理工作,比如定时器,事件等
错误处理
1,compontentDidCatch(error,info)
在整个生命周期中可以捕获js错误
ref
ref属性同vue,可以直接用其引用组件的实例
ref只能通过class声明和添加,因为函数式组件没有实例
import React,{Component,createRef} from 'react'
class App extends Component{
constructor(){
super()
//创建ref标识
this.inputRef=createRef
}
componentDidMount(){
console.log(this.inputRef)
}
render(){
return(
<input type='text' ref={this.inputRef}>
)
}
}
React Hooks
hooks使得在函数式组件中,也能运用像class组件一样的state和生命周期的特性
State Hook
//useState是react包提供的一个方法
import React,{useState} from 'react'
const Counter=()=>{
const [count,setCount] = useState(0);
return(
<p>点击{count}次</p>
<button onClick={()=>setCount(count + 1)}>点击</button>
)
}
Effect Hook
import React, { useEffect, useState } from 'react'
const Test = () => {
let [count, setCount] = useState(0)
useEffect(() => {
setTimeout(() => {
setCount(count + 1)
}, 1000)
})
return (
<p>自增{count}次</p>
)
}
**React Hooks 的规则
1,只能在函数的顶层调用
2,不要在循环,条件,嵌套中调用
**内置hooks api
基础 Hook
//类似class的状态
useState
//类似class的didMount和didUpdate,但是不同的是,会在浏览器绘制完dom之后
useEffect
//类似vue的inject方式从祖先节点传递数据
useContext
额外的 Hook
//类似vuex的redux实现,用于状态管理
useReducer
//
useCallback
useMemo
useRef
useImperativeHandle
useLayoutEffect
useDebugValue
组件通信
1,父组件向子组件通信
父组件将自己的状态通过props传递
父组件通过ref标记拿到子组件,调用子组件相关方法变更子组件状态
2,子组件向父组件通信
父组件将整个自己通过props传递给子组件,子组件可以通过调用父组件事先写好的方法变更状态
3,隔代通信
使用context
4,全局通信
使用redux
HOC(高阶组件)
Higher-Order Components 是一个函数,可接受一个以组件形式的参数并返回一个新组件
const NewComponent = higherOrderComponent(prevComponent)
比如我们想要一个版权注入
const withCopyRight = (wrapperComponent) =>{
return class NewComponent extends Component{
render(){
<Fragment>
<wrapperComponent />
<div>copyright info xxx</div>
</Fragment>
}
}
}
使用
const copyRightApp=withCopyRight(App)