React基础

前提

React 是 Facebook 公司写的 MVC 框架,但是 React 实际上不太关心 M 和 C,只关注 V 层
React 16 之前用的 diff 算法,16之后采用 Fiber 算法。之前的更新过程是同步的, Fiber 将单线程的任务一一分片,这样唯一的线程就不会被独占,其他任务依然有运行的机会
特点:1. 虚拟 DOM 2. 组件系统 3. 单项数据流 4. JSX 语法
组件:
同时包含了 html css js image 的聚合体
React 解决 CSS 冲突:在 webapck 的 module 中添加 css ,将 css 看做单独的模块。除此之外还有 vue 的 scrope

安装

  1. npx create-react-app 项目名称 推荐,避免全局安装
  2. npm i create-react-app -g 不推荐
  3. cd 进入项目根目录
  4. yarn eject 将配置文件单独抽离(可选)
  5. yarn start 运行
  6. 页面报错:@babel/plugin-transform-react-jsx 解决:yarn xxxx 安装

安装说明
  1. react :react 的顶级库。用于创建虚拟 DOM ,组件的声明周期都在这个包中
  2. react-dom:因为 react 的运行环境有很多,在浏览器上要进行 DOM 操作,而在 app 端需要 react-native 。我们要在浏览器中运行就需要 react-dom ,将JSX语法变成浏览器能识别的东西。最主要的应用场景是 ReactDOM.render()
  3. react-script:react 的运行脚本和配置
  4. create-react-app 为 react 脚手架,因为不支持 jsx 语法,需要通过 webpack 配置 bable 。脚手架帮我们做好了
  5. 一直要用的 -S 安装,工具装 -D 里去
  6. 特别的:import React from ‘react’ 和 import ReactDOM from ‘react-dom’ 必须是 React ReactDOM 这两个名字,否则报错

目录
根目录
	config				抽离的 webpack 配置文件
	src
		index.js		webpack 4.x 约定的入口文件 ./src/index.js

index.js

index.js 主要通过 ReactDOM.render() 渲染组件,然后挂载在容器上
serviceWorker.unregister() 该方法作用目前未知,等知道了过来补充

import React from 'react'
import ReactDOM from 'react-dom'

const myH1 = React.createElement('h1', { id:'myH1',title:'这是h1' }, 子节点) 		
	创建虚拟 DOM								
	参数一:标签类型
	参数二:object||null 设置 DOM 属性
	参数三往后:子节点,可以是文本也可以是虚拟 DOM 对象,实现嵌套关系

ReactDOM.render( myH1 , document.getElementById('app'))
	渲染虚拟 DOM 成真实 DOM
	参数一:虚拟 DOM 对象
	参数二:指定 DOM 元素作为容器(mountNode)

可以这么干,但没必要。想要直接写 html 语法的东西,简单点。

  1. 测试
const myText = <div>测试</div>
ReactDOM.render( myText , document.getElementById('app'))

报错:提示可能需要合适的第三方 loader 工具转化。JS 中不能直接写 HTML 语法
  1. 通过 bable 转换 JS 中的 HTML 语法,从而让 JS 支持 HTML 语法,这种新的写法叫 JSX 语法

!!!这条还在测试,不成功
直接上脚手架就好了。。自己配太麻烦

npm i @babel/core @babel/plugin-transform-react-jsx babel-loader -D

https://blog.csdn.net/zhao1949/article/details/76913442

jsx 本质还是在运行时通过 bable 转化为 React.createElement() 这种形式


组件

class 组件和 funciton 组件区别:
1.都有 props ,访问方式不一样
2.构造函数没有 state , 没有生命周期钩子,没有私有数据(对比 Vue 的 data )
3.本质区别:有无 state 和 生命周期函数
无状态组件效率比有状态组件稍高一些。但是常用的还是class组件

  1. class 组件
import React from 'react'

class A extends React.Component { extends React.Component 的目的是让我们自定义的 A 类继承 React 组件特性
  render() {
    return (
      <div>
        this is my A react-component
        {this.props.children}	插槽
      </div>
    )
  }
}

  1. 函数式组件( pureComponent无状态组件 )
    接收唯一带有数据的 props(代表属性)对象与并返回一个 React 元素。这类组件被称为“函数组件”,因为它本质上就是构造函数
import React from 'react'

function B (props){
  return (
    <div>
      this is my b react-component
    </div>
  )
}

组件生命周期

http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

1. 初始化阶段

1.constructor(){} 在组件挂载之前执行

constructor(){
  1.通过super继承父组件身上的东西
  super()
  2.通过 this.state 初始化 state
  this.state={}
  3.为事件处理函数绑定实例
  this.fn=this.fn.bind(this)
  4.在构造函数中不要调用 this.setState() 方法,直接给 state 赋值
}

5.避免将 props 的值复制给 state!这是一个常见的错误
constructor(props) {
  super(props);
  // 不要这样做
  this.state = { color: props.color };
}
如此做毫无必要(你可以直接使用 this.props.color),同时还产生了 bug(更新 prop 中的 color 时,并不会影响 state)

2.static getDerivedStateFromProps(nextProps, prevState) 最新,如果写这个会造成 componentWillMount(){} 的钩子不能用
组件实例化后、接受新的 props 后、父组件修改传递过来的 props 触发。

16+数据请求
static getDerivedStateFromProps(nextProps, prevState){
  				新属性,旧状态
  console.log(nextProps,prevState)
  return null	必须返回一个对象来更新状态。
}

3.componentWillMount(){}

16-数据请求
将在17版本后弃用,用来数据请求和状态的修改。类比 Vue 的 create + beforeMount

4.render()
render 方法是必须的,当被调用时,计算 this.props 和 this.state,将React 元素转成JS能识别的对象,生成虚拟 DOM 节点,并转成原生的JS节点。返回以下一种类型:

1.React 元素,可以是 dom 元素,也看可以是用户自定义组件
2.字符串或数组,以文本节点渲染 dom 中
3.Portals 16版本提案,可以使组件脱离父元素直接挂载 DOM 任何位置
4.null / false/ ReactDOM.findDOMNode(this) 什么也不渲染

5.componentDidMount(){}
在render后,完成挂载,生成真实 DOM 调用。第三方的实例化。
通常上讲这里是写死的数据,活的数据应该在updata钩子内,但是写在updata内不好,我们一般在这里设置定时器异步处理

第三方实例化 + ajax 请求
componentDidMount(){
  console.log('componentDidMount')
}
2. 更新阶段
componentWillReceiveProps(){}

conmponentDidUpdate(){}		常用
3. 卸载阶段
componentWillUnmount(){}		常用
4. 错误处理

组件通讯
  1. 父子通讯
1.传递父组件的 state,子组件通过 props 接受
2.通过 ref 链实现父组件获取子组件的状态
ref 可以接受字符串,也可以接受一个函数为参数
2.1.字符串
class GrandFather extends React.Component {
  constructor(){
    super()
    console.log(this.refs)	这里输出为空:因为 ref 本身是作为渲染结果被创建的,在初始渲染的时候你不能访问它们
    它们还不存在 $refs 也不是响应式的,因此你不应该试图用它在模板中做数据绑定。
    如果想要正确的输出 this.refs 可以设置 setTimeout() 或者在 componentDidMount(){} 钩子内输出试试
  }
  change=()=>{
    this.refs.father.setState({
      money:500
    })
  }

  render(){
    return (
      <div className="App">
        <Father ref="father"></Father>
        <button onClick={this.change}>修改</button>
      </div>
    );
  }
}

class Father extends React.Component{
  constructor(){
    super()
    this.state={
      money:1000
    }
  }
  render(){
    return (
      <Fragment>
        我有{this.state.money}
      </Fragment>
    )
  }
}

2.2.函数
ref={ el => this.father = el}
el 表示当前被挂载的子组件
this 表示父组件
当函数做参数的时候,可以直接通过 this.father 访问,这个函数将当前组件挂载在 this 身上

  1. 子父通讯(自定义事件)

父组件将可以修改 state 的方法传递给子组件,子组件通过 props 接收,然后调用方法

  1. 跨组件通讯(爷孙关系,同一个根组件)
    层层传递很麻烦,在 Vue 中我们使用bus总线,在 react 中使用 context ,两者效果一致
    Context 设计目的是为了对于一个组件树而言是‘全局’的数据
1.创建 Context
const MyContent = React.creatContext('默认值')
2.<MyContent.Provider value='xx'>标签包裹目标组件
3.在需要使用的子组件内定义静态属性 contextType 
static contextType = MyContent
4.在子组件任何位置通过 this.context 访问
------------------------------------------------------
const Fcontext = React.createContext('10000')
class Home extends React.Component {
  render() {
    return (
      <div className="App">
        <Fcontext.Provider value='1000'>
          <GrandFather />
        </Fcontext.Provider>
      </div>
    );
  }
}

class Son extends React.Component {
  static contextType = Fcontext
  render() {
    return (
      <Fragment>
        我有{this.context}
      </Fragment>
    )
  }
}

  1. 多组件共享
    1.flux
    2.redux
    3.mobx
高阶组件(hoc)

高阶组件目的就是为了组件的复用

const Hoc = (Comp)=>{
  return (
    class banner extends React.Component{
      banner(){
        return 'banner'
      }
      render(){
        return (
          <Comp banner={this.banner}></Comp>
        )
      }
    }
  )
}
class A extends React.Component{
  render(){
    return(
      <div>
        <h3>A组件</h3>
        {this.props.banner()}
      </div>
    )
  }
}
const HocA = Hoc(A)

class C extends React.Component{
  render(){
    return (
      <div>
        <HocA></HocA>
        <HocB></HocB>
      </div>
    )
  }
}


样式

在 react 中,没有 Vue 的 scoped 这样的指令,因为根本没有指令的改变。
解决办法:为 css 启用模块化
webpack.config.js

在 css-loader 后追加参数?,与 get 参数形式一致。
其中有一个固定参数 modules,表示为 css 添加模块化
css 模块化只针对类名和 id 模块化,对标签无效

rules:[
  { text:/\.css$/, use: ['style-loader', 'css-loader?modules'] }
]

使用 localIdentName 自定义生成的类名格式,可选的参数有:
 - [path]  表示样式表 `相对于项目根目录` 所在路径
 - [name]  表示 样式表文件名称
 - [local]  表示样式的类名定义名称
 - [hash:length]  固定位的hash值
例:{ test: /\.css$/, use: ['style-loader', 'css-loader?modules&localIdentName=[path][name]-[local]-[hash:5]'] }

组件.js

如果没有 css 模块化,这样导入的 css 为空对象,模块化后,css 导出一个对象
对象内真正的类名不在是 .title 的 title 类名,而是一串经过处理后的字符串。我们通过 cssObj.title 添加对应的字符串所表示的类名

import cssObj from './index.css'	

在需要的标签上,使用 className 指定模块化的样式:
<div className = { cssObj.title }>    对应 .title{}

我们也可以混合使用字符串和类名
<div className = { cssObj.title + 'text' }>
或者
<div className = { [cssObj.title, 'test'].join(' ') }>

index.css

.title{
  font-size:14px;
  color:red;
}

如果有一个类名我们不想将其模块化,我们可以使用 :global()包裹类名
全局生效的,不会被 `css-modules` 控制,定义的类名是什么,就是使用定义的类名`className="类名"`
:global(.title){
  font-size:14px
}

:local()包裹的类名,是被模块化的类名,只能通过`className={cssObj.类名}`来使用
同时,:local() 默认可以不写,这样,默认在样式表中定义的类名,都是被模块化的类名

  1. 外部引入
没有作用域,全局生效
import './index.css'
  1. 行内样式
import React from 'react'
import './index.css'

1.行内样式接受 style 属性接受一个对象为属性值,CSS 中的 - 用驼峰代替
class C extends React.Component {
  render() {
    return (
      <div style = {{ fontSize:'red',backgroundColor:'bule' }}>
        this is my C react-web
      </div>
    )
  }
}

2.我们发现如果行内样式很多的话看起来很麻烦,可以将样式以变量的形式封装
const styles = {
  div:{background:'red',fontSize:'14px'},
  p:{xxx}
}
<div style = { styles.div }>

3.当文件很大的时候,我们可以抽离成单独的样式表模块,然后再组件内引入
export default styles
import style from './styles'
  1. 样式组件
    安装:yarn add styled-components
    HeadStyledComponent.js
import styled from 'styled-component'

const HeadStyledComponent = styled.header`
这里写样式
`
export default HeadStyledComponent 

Head.js

import React from 'react'
import HeadStyledComponent from './HeadStyledComponent'

class Head extends React.Component{
  render(){
    return(
      <HeadStyledComponent>
        菜谱大全
      </HeadStyledComponent>
    )
  }
}
export default Head 

列表循环
  1. 在 react 中,与 Vue 类似,在循环的时候也需要 key 来标识。react 中,key 加给直接被循环控制的根元素上。
  2. 在通过 reudx 获取数据的时候,数据是从无到有,经过多次渲染。在 render(){} 中 console.log(this.props) 会发现数据从无到有的过程。所以我们在做 拿数组 – map 循环数组的时候,要对数据是否拿到进行判断。需要注意的是:这里拿的数据必须精确到数数组这一层和数组上一层。否则也是会出问题
对数据判断,有才赋值,没有为空,下边的if不会走,就不会渲染,避免报错
必须这么写,否则会出错

renderItem=()=> {
						数据上一层			数据本身
  let lists = this.props.home[1] &&this.props.home[1].list
	if(lists){
  	  return lists.map((item,index) => {
  	  return <Item {...item} index={index} key={item.title}></Item>
	})
  }
}
import React from 'react'
import store from '../../store'

function Item(props){
  return (
    <li>{props.item.text}</li>
  )
}


class TodoContent extends React.Component {
  constructor(){
    super()
    this.state={
      todos:store.getState().todos
    }
  }
  renderItem = () => {
    return this.state.todos.map(item => {
      return (
      	key 要加载这里,加载 map 内的 DOM<Item item={item} key={item.id}></Item>
      )
    })
  }
  componentWillMount(){ //事件订阅
    store.subscribe(()=>{
      // 重新获取最新状态
      this.setState({
        todos:store.getState().todos
      })
    })
  }
  render() {
    return (
      <div className="todo_inptu">
        <ul>
          {this.renderItem()}
        </ul>
      </div>
    )
  }
}

export default TodoContent

props (read-only)

不管是在 Vue 还是在 React 中,props 在子组件内是只读的,修改的操作需要在父组件内。
在无状态组件中需要构造函数传入props 接收父组件传递的属性
在class直接通过 this.props.xx 访问,特别的: constructor 构造函数内需要 props 参数,才能正确访问。
并且需要 super(props) 继承过来???测试不需要 super(props)???

function B( props ){
  return (
    <div> { props.xx } </div>
  )
}

class B extends Component{
----------------------class
  constructor(){
    super()
    console.log(this.props)	报错
    console.log(props)		报错
  }
-----------------------------
  constructor(props){
    super()
    console.log(this.props)	undefined
    console.log(props)		正确
  }
-----------------------------------
  constructor(props){
    super(props)			其实不是很明白这里super(props),测试super()也不报错
    console.log(props)		正确
  }
-----------------------------------
  render(){
    return (
      <div>
        {this.props.xx}		这里直接通过 this.props 可以访问
      </div>	
    )
  }
}

super()

class Person {
  constructor(name,age){
    this.name=name
    this.age=age
  }
  sayHey(){
    console.log('hey')
  }
}

class Chinese extends Person {
  constructor(){
    super()	
    1.直接super() new 出来的实例 name 和 age 为 undefined。删除整个 constructor 后正常
    2.如果一个子类通过 extends 继承父类,并且手写了 constructor 那么在子类的 constructor 中必须先调用 super()
    3.super() 是父类的构造器引用(可能类似与借用继承 Father.call(this,arg1,arg2)}
  
    4.解决 undefined :给子类的构造方法传参,然后调用 super() 方法内写入参数
  constructor(name,age){
    super(name,age)
  }
}

var a1 = new Chinese('jack',23)
console.log(a1)
a1.sayHey()

解构赋值传 props,避免手写过多

class A extends React.Component {
  render(){
    return (
      <B { ...this.state.someObj }></b>
    )
  }
}

静态属性和静态方法

class A {
  在类中 用 static 关键词定义的属性就是该类的静态属性,只能通过 class.props 访问,不能在实例中继承。
  static info = 'static props'	这是静态属性
  static changeState(){
    这是静态方法
  }
}

实例方法

在react中,组件内的方法存在 this 丢失的问题,我们有三种解决方案
class App extends React.Component{
  1.在构造器中通过 bind() 绑定 this(不推荐)
  constructor(){
    spuer()
    this.add.bind(this)
  }
  add(){xxx}
  
  2.箭头函数声明(推荐)
  add=()={}
  
  3.调用时绑定 this(需要传参时推荐)
  render(){
    return(
      <div onClick={this.add.bind(this)}></div>
    )
  }
}

方法传参

class App extends React.Component{
  add=(arg1,arg2)={}
  render(){
    return(
      1.标准格式:通过包裹一层箭头函数传参
      <div onClick={()=>{this.add(arg1,arg2)}}></div>
      2.通过 bind 传参
      <div onClick={this.add.bind(this,arg1,arg2)}></div>
    )
  }
}

属性验证
npm i prop-types -S

imoprt PropTypes from 'prop-types'

class_name.propTypes = {
	属性:PropTypes.String,
	属性:PropTypes.类型
}


state

状态会带来管理的复杂性,我们多使用无状态组件,少用有状态组件。有利于性能优化
Reactthis.state={} 类比 Vuedata(){return {}}
第一种state定义方式(推荐)

calss App extends Reate.Component{
	constructor(){
		super()		这个不要忘记
		this.state={
			name:'zhangsan',
			age:23
		}
		this.change.bind( this )
	}
	change(){
	  在对 state 修改的操作中,我们使用 this.setState(newState, callback) 方法,不要在 constructor 中使用。
	  this.setState() 方法为异步的,接受两个参数。
	  第一个参数可以是一个对象或者一个函数返回一个对象
	  this.setState({
	    key:vaule
	  })
	  如果第一个参数为函数则需要 return 出一个对象,这个函数有两个参数,分别为 state 和 props
	  this.setStaet((state, props) => ({
	    key:vaule
	  }))
	  第二个参数为回调函数,在state改变后执行,如果我们在改变状态后需要最新的值,则需要在回调里取
	}
	render(){
		return (
			<div> { this.state.name } </div>
		)
	}
}

第二种方式(不推荐)

calss App extends Reate.Component{
	state={}
}
状态提升

放在共同组件内,实现多组件共享状态

state/data 与 props

props 从外接传过来的
state/data 组件私有的,一般从 Ajax 获取到的数据
props 传过来的是只读的,不能被重新赋值
state/data 中的数据,都是可读可写的


事件

react 事件采用小驼峰,并不是原生事件,是合成事件,不考虑兼容。传入函数作为处理程序而非字符串。
原生JS:<button onclick="activateLasers()"></button>
React : <button onClick={activateLasers}>Activate Lasers</button>
阻止默认行为不能用 return false,需要事件处理程序中显式使用 e.preventDefault()
在 JSX 语法中的虚拟DOM上绑定事件的时候,通常 this 会丢
解决办法:
1.通过箭头函数在声明时给定 this 指向( class fields 语法)
fn = () => { xx }
2.通过类的constructor通过bind绑定函数this
constructor(){ this.fn=this.fn.bind(this) }
3.在事件绑定时通过bind()方法绑定 this
<div onClick={ this.fn.bind(this) }><div>
4.在事件绑定时用箭头函数
<div onClick={ e => this.fn(e) }><div>
区别:4可能额外的重新渲染,推荐使用 class fields 语法来避免这类性能问题
事件源
事件触发形式:on addEventListner
事件类型
事件handler

react 中 event 对象不由浏览器提供,是自己内部构建的。
console.log(ev) 中值都为null,但是使用方式与原生一致,并且有值
事件传参

我们一般在父组件中定义方法,然后通过 props 传递,在子组件中传参调用
在 react 单括号中,绑定事件时候如果括号传参,会自定执行。所以正确的事件传参形式为this.fn.bind( this, arg1,arg2 )

问题:
<div onClick={ this.fn(arg1,arg2) }	这里函数自动执行一次后失效,绑定失败

正确方式:
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

区别:
这两种情况,React 的事件对象 e 会被作为第二个参数传递
如果通过箭头函数的方式,事件对象必须 显式 传递
而通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。

class A extends Component{
  constructor(){
    super()
    this.state={
      name:'zhangsan'
    }
  }
  sum(a,b){
    alert(a+b)
  }
  render(){
    let { name } = this.state
    return (
      <div onClick = { this.sum.bind( this,1,2 ) }>
        <B name={ name }></B>
      </div>
    )
  }
}
class B extends Component{
  render(){
    let { name } = this.props
    return (
      <Fragment>

      </Fragment>
    )
  }
}

反向代理

安装中间件:yarn add http-proxy-middleware

新建文件:src/setupProxy.js

引入中间件
const proxy = require('http-proxy-middleware')

module.exports = function (app) {
  app.use(proxy('/secoo', {
    target: 'https://las.secoo.com',
    changeOrigin: true,
    secure: false,
    pathRewrite: {
      "^/secoo": ""
    }
  }))
  
  第二个反向代理
  app.use( proxy( '/xxx', {
    
  }))
}

路由
  1. 安装
    3.x
    yarn add react-router
    4.x
    yarn add react-router-dom

  2. 两种模式( HashRouter / BrowserRouter )
    1.老版本的 HashRouter :通过 hash 存储不同状态的 history 信息,对应 createHashHistory ,通过检测 location.hash 值的变化,使用 location.replace 方法实现 url 跳转。通过注册监听 window对象上的 hashChange 事件来监听路由变化,实现历史记录的回退
    2.高版本浏览器的 BrowserRouter:利用 HTML5 里的 history 对应 createBrowerHistory,使用包括 pushState,replaceState 方法进行跳转。通过注册 window 对象上的 popstate 事件来监听路由变化,实现回退
    需要后端支持

  3. 实现:
    <Route path=" / " component={ Home }>:路由展示区
    exact:路由完全匹配

路由在入口文件使用 Router 包裹路由组件
index.js

1.引入 HashRouter 
import {HashRouter as Router} from 'react-router-dom'

2. 包裹需要路由的根组件
ReactDOM.render(
<Router>	//包裹
  <App />
</Router>, document.getElementById('root'));

App.js

import { NavLink,Route,Link } from 'react-router-dom'
function App() {
  return (
    <div className="App">
      <nav className="nav justify-content-center">
        <NavLink activeclassName="active" className="nav-link active" to="/home">Home </NavLink >
        <NavLink activeclassName="active" className="nav-link" to="/mine">Mine</NavLink >
        <NavLink activeclassName="active" className="nav-link disabled" to="/list">List</NavLink >
      </nav>
       Route 就是路由展示区
      <Route path="/home" component={Home}></Route>
      <Route path="/mine" component={Mine}></Route>
      <Route path="/list" component={List}></Route>
    </div>
  );
}
  1. a标签也可以,但是浏览器会显示一次跳转的状态,就是浏览器的刷新按钮在转圈圈
  2. < Link to=" " >标签可以避免 a 标签的问题。
  3. <NavLink>用来路由激活的标签,除此之外与 Link 没什么区别,添加 activeClassName 属性可以实现动态添加样式
重定向
重定向

exact 路由完全匹配,避免’/’ 被所有匹配到

1.引入 Redirect
import { Redirect,Route } from 'react-router-dom'

第一种:
<Route path="/" exact render={()=>(<Redirect to='home' />)} />
注意:必须加上 exact ,否则造成死循环

第二种:
<Route path="/" from='' to='' exact />
注意:使用 from='' to='' 需要在外边加上switch

第三种:(此方法取巧)
<Route path="/" component={ Home } exact />
路由激活:

imoprt { NavLink } from ‘react-router-dom’

<NavLink activeClassName = "active" className=""  />
路由传参

路由组件的props上具备几个属性

history
  push
  replace
  goBack
location
  pathname
  search
  state
match

push会存进浏览器历史中 replace 不会存入历时记录中

传递:
to={{ pathName:'/mine/login',search:'?a=1&b=2', state:{count:1}  }}

二级路由
二级路由与一级路由大致相同,在子路由中再添加路由展示区<Route path='' component={xx}>即可
路由监听

切换路由不能滚动问题
将APP变成路由组件

withRouter包裹 App组件

属性变化钩子
componentWillReactiveProps()

错误匹配
高阶组件
withRouter
问题:为什么Vue有导航守卫监听路由变化,react为什么没有

React-Hooks

可以让函数式组件使用 satae 、生命周期钩子、useContext、useRef,16.7版本以后出现的。
只能在顶层调用 Hooks 不要在循环,条件调用 hooks。

安装

npm i react-hooks -D
npx create-react-app react-hooks

useState

import React, {useState } from 'react'

const Hooks = () => {
  const [count, setCount] = useState(0)
  count是state的属性,useState()内是count的初始值,setCount是操作count的方法
  return (
    <div>
      <button onClick={()=>setCount(count+1)}>修改count</button>
      <p>count:{count}</p>
    </div>
  )
}

export default Hooks

uesEffect
类似componentDIdMount 或 componentDidUpdate

import React, { useState, useEffect } from 'react'

const Hooks = () => {
  const [count, setCount] = useState(0)
  useEffect(() => {
    document.title = `你点击了${count}次`
  })
  return (
    <div>
      <button onClick={() => setCount(count + 1)}>修改count</button>
      <p>count:{count}</p>
    </div>
  )
}

export default Hooks
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值