rrr

React

为什么要使用react-dom?

经过后面的知识已经了解到有react-native的存在,我们知道RN属于原生应用的开发语言原生应用没有浏览器的存在,所以把react 的核心知识放在了react中让RN和web开发同时使用,而react-dom则是如何在react中进行dom渲染的核心内容,我们常使用react-dom中的render方法。

组件与元素
元素

html中原生的节点,跟原生的写法一样,小写。

组件

组件的第一个字母大写。

类组件的写法
函数式组件写法

存在缺点:没有生命周期钩子和状态。

jsx
jsx简介

一种语法糖通过webpack中的babel来编译jsx,内部通过js中的createElement()方法,来渲染一个dom节点

createElement('标签名'{'属性'}{'子节点'})
vscode中快速生成jsx基本代码块
  • vscode中如下插件

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mD4XZ3NN-1583310091040)(C:\Users\yuyang\AppData\Roaming\Typora\typora-user-images\1580697917111.png)]

  • 在jsx文件中输入rcc回车即可生成jsx基本代码块模板

css的引入
css-in-js

下载包:styled-components

会给元素添加一个唯一的类名

//footer.js
import styled from 'styled-components'

const FooterWrap = styled.div `
  font-size: ${ props => props['font-size'] }
`

export {
  FooterWrap
}

//Footer.jsx
import React from 'react'

import { FooterWrap } from './footer'

function Footer() {
  return (
    <FooterWrap font-size="200px">footer</FooterWrap>
  )
}

export default Footer
styled-component中编写样式出现相应的提示

需要安装如下插件:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2pYql0kz-1583310091042)(C:\Users\yuyang\AppData\Roaming\Typora\typora-user-images\1580698112461.png)]

props
props.children

可以让组件中的子元素显示,与vue中的slot的功能一样,react中没有slot插槽的概念。

//List.jsx组件
<li>
  {this.props.children}
</li>
//父组件
  <List keyword={this.state.keyword}>
      <div>hello</div>
  </List>
defaultProps

当不传值 的时候设置一个默认值。

 static defaultProps =  {
     keyword:'abc'
 }

//写在外面
List.defaultProps={
     keyword:'abc'
}
使用prop-types进行prop的类型的检查

使用:引入prop-types包

//具体的用法参考npm
//子组件中对父组件中传过来的数据进行验证  
static propTypes={
       //父组件中传过来的keyword的类型必须是string,并且不能为空
       keyword:propTypes.string.isRequired 
  }
state
setState()

当state中的数据发生变化时,需要使用setState(),使用setState()函数就调用render()函数,注意这与Vue不同。

当状态中存储一个数组,为什么可以对数组进行push()而不会报错?

当state中存储的数据发生改变的时候,需要调用setState()进行修改,但是数组是一个地址的引用,而push数组只是改变它的元素,并没有改变它的地址,所以push不需要调用setStat(),但是也没有改变state,需要使用以下的方法:

this.setState({
    //产生一个新的数组
    arr:[...this.state.arr,e.target.value]
})
setState()是异步函数,要想拿到实时更新的数据,需要使用延时器,把他放大下一个事件循环之中,或者使用下面的写法来实现,vue中通过$ticknext()来实现
  this.setState( {
        keyword: value
    }, () => {
      console.log(this.state.keyword)
    })
  }
setState()引用原值的问题?
//使用以下的方法,其中state保证是最新的值,防止意外的修改
this.setState(state => {
      return {
        keyword: value,
        arr: [
          ...state.arr,
          value
        ]
      }
    })
render()

父组件的 render()函数调用,子组件的render()一定调用。

state

主要用于保存、修改、控制自己 的可变状态,state在组件的内部初始化,只能在组建的的内部进行访问和修改,你可以认为组件是一个局部的只能被自身控制的数据源,通过setstate()进行更新,会造成组件的重新的渲染。

pureComponent

定义组件使用pureComponent,可以使更新数据时如果数据没有发生改变就只进行虚拟dom树的比对而不重新渲染。

受控组件与非受控组件

React组件的数据渲染是否被调用者传递的props完全控制,控制则为受控组件,否则非受控组件。

受控组件

组件中的属性值完全依赖父组件。

非受控组件

通过ref来实现,进行dom操作

//从react中解构出一个react对象
import React, { Component, createRef } from 'react'

class Form extends Component {
  constructor() {
    super()
     //把对象的执行结果赋值给this.inputRef
    this.inputRef = createRef()
  }

  state = {
    // keyword: '',
    arr: ['a', 'b']
  }
  handleKeyUp(e) {
    if (e.keyCode === 13) {
      let input = this.inputRef.current
      this.props.onReceiveKeyword(input.value)
      input.value = ''
      // this.setState({
      //   keyword: ''
      // })
    }
  }

  render() {
    // console.log(0)
    return (
      <>
        <input
          //设置一个ref属性
          ref={this.inputRef}
          onKeyUp={this.handleKeyUp.bind(this)}
          type="text"
        />
      </>
    )
  }
}

export default Form
事件处理
自定义事件
在constructor中定义bind(this)

​ 直接在组件内定义一个非箭头函数的方法,然后在render里直接使用onClick={this.handleClick.bind(this)}(不推荐),因为根据bind的特性,每调用一次click都会创建一次handleClick函数,性能很低,应该直接在组件内定义一个非箭头函数的方法,然后在constructor里bind(this)(推荐)

在事件中传递参数

通过下面的方法传参。

handleClick=(value)=>{
    console.log(value)
}


render(){
    return (
<button onClick={()=>{
    this.handleClick('abc')
}}></button>
)
}
handleClick=()=>{
    return (value)=>{
    console.log(value)
    }
}


render(){
    return (
<button onClick={
    this.handleClick
}></button>
)
}
在事件中传递参数,使用科里化,可以让代码更加的优雅美观
getDerivedStateFromProps()钩子函数

触发这个钩子的四种场景。

constructor:创建的时候。

New props:创建一个新的属性时候。

setState():修改组件内的状态的时候。

foreceUpdate():执行强制更新函数的时候。

如果在父子组件的componentDidMount()钩子中同时做了相应的修改,那么子组件中的getDerivedStateFromProps()钩子是如何执行的?子组件中的render()函数有事如何执行的?
  • 当在父子组件的componentMount()钩子中做相应的修改后,子组件中的这个钩先执行,父组件中的这个钩子后执行,但是他们中的代码几乎同时执行,所以此时getDERIVEDstateFromOProps()钩子和render函数合并为一个

  • 如果需要他们不进行合并,可以将父组件的操作放入下一个事件循环当中(serTimeout())

与老钩子函数中的
Context(组件件信息传递)

与Vue中的provide和inject(提供器和注入器)相似。

//color_context.js  

//创建一个context
import React,{createContext , Component} from 'react'

const colorContext = createContext()

//conext中的provider(提供器对象),和Consumer(注入器对象)
const {
    Provider,
    Consumer
}=colorContext

export {Provider,Consumer}

export default colorContext
//index.js
import ReactDom from 'react-dom'
import {Provider} from  './pages/context/color_context'
import Parent from './pages/context/Parent'
ReactDom.render(
    //提供器提供了属性value,其中存储了一个对象
    <Provider value={{color:'red'}}>
         <Parent></Parent>
    </Provider>,
    document.getElementById('root')
)

注入方式一:

import  React , {Component} from 'react'

import colorContext from '../context/color_context'
import {Consumer} from '../context/color_context'
export default class Child1 extends Component{
    //静态属性:挂载到当前的类上
    //将colorContext注入到静态属性中,可以在context中提取提供器提供的数据
    static contextType=colorContext

    render(){
        return (
            <>
              <div style={{color:this.context.color}}>child1</div>
            </>
           
        )
    }
}

注入方拾二:

import  React , {Component} from 'react'

import colorContext from '../context/color_context'
import {Consumer} from '../context/color_context'
export default class Child1 extends Component{
    render(){
        return (
             // 提取器对象,获得提取器对象中的数据需要一个回调函数,其中的对象就是一个包括提供器中所有数据的对象
             <Consumer>
                 {
                     (value)=>(<div style={{color:value.color}}>child1</div>)
                 }
             </Consumer> 
        )
    }
}
让context变成组件(增强能力)
//color_context.js
import React, { createContext, Component } from 'react'

const colorContext = createContext()

const {
  Provider,
  Consumer: MyConsumer
} = colorContext

//自定义一个提供器,将原生的提供器包裹在里面,增加一些其他的功能
class MyProvider extends Component {
  constructor() {
    super()
    this.state = {
      color: 'red'
    }
  }

  changeColor = (color) => {
    this.setState({
      color
    })
  }

  render() {
    return (
      <Provider
        value={{
          color: this.state.color,
          changeColor: this.changeColor
        }}
      >
        {this.props.children}
      </Provider>
    )
  }
}

export {
  MyProvider,
  MyConsumer,
  colorContext
}
//index.js
//用于解决,渲染的dom外只有唯一的包裹的元素,可以使用div,但不好 ,可以使用<></>
import React,{Fragment} from 'react'
import ReactDom from 'react-dom'
import {MyProvider} from  './pages/context/color_context'
import Parent from './pages/context/Parent'
ReactDom.render{
    //使用自定义的提供器
    <MyProvider value={{color:'red'}}>
         <Parent></Parent>
    </MyProvider>,
    document.getElementById('root')
)

//Parent.jsx
import React,{Component} from 'react'
// import Child1 from './Child1'
import {colorContext} from './color_context'
class Parent extends Component{
    static contextType=colorContext
    handleClick(green){
         this.context.changeColor(green)
    }
    render(){
        return (
            <div style={{color:this.context.color}}>
             parent
             <button onClick={()=>{
                 this.handleClick('blue')
             }}>change</button>
            </div>
        )
    }
}

export default Parent
高阶组件

一个函数,可以把一个组件当做他的函数参数,这个函数就是高级组件。

//hoc.js
import React, { Component } from 'react'
export default (Comp) => {
  return class extends Component {
    render() {
      return (
        <Comp title="hello"></Comp>
      )
    }
  }
}
/index.js
//用于解决,渲染的dom外只有唯一的包裹的元素,可以使用div,但不好 ,可以使用<></>
import React,{Fragment} from 'react'
import ReactDom from 'react-dom'
import {MyProvider} from  './pages/context/color_context'
import Parent from './pages/hoc/Hoc'
ReactDom.render{
    //使用自定义的提供器
    <MyProvider value={{color:'red'}}>
      <Hoc></Hoc>
    </MyProvider>,
    document.getElementById('root')
)

//Hoc.jsx
import React,{Component} crom 'react'

import hoc from './hoc'

class Hoc extends Component {
    render(){
        console.log(this.props)
        return (
        <div>
          aaaaaa
        </div>
            )
    }
}

//注意暴露一个高阶组件函数
export default hoc(Hoc)
渲染属性(RenderProps),增强组件

//RenderProps.jsx
import React, { Component } from 'react'
import RenderPropsChild from './RenderPropsChild'
export default class RenderProps extends Component {
  render() {
    return (
      <div>
        //父组件中定义一个函数属性,还可以在渲染函数中传入一个组件
        <RenderPropsChild
          render={
            (item) => {
              return (
                <div style={{color: 'red'}}>{item}</div>
              )
            }
          }
        ></RenderPropsChild>
      </div>
    )
  }
}


//RenderPropsChild.jsx
import React, { Component } from 'react'

export default class RenderPropsChild extends Component {
  state = {
    item1: 'list item 1',
    item2: 'list item 2'
  }

  render() {
    return (
      <div>
        <h1>child</h1>
        <div>
          {
            this.props.render(this.state.item1)
          }
        </div>
        <div>
          {
            this.props.render(this.state.item2)
          }
        </div>
      </div>
    )
  }
}

常用高阶组件
  • memo()
  • withRouter(),给组件添加路由信息
redux (React状态管理)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-81EslQSt-1583310091044)(C:\Users\yuyang\AppData\Roaming\Typora\typora-user-images\1575355532702.png)]

基本实现
//创建一个仓库
const {createStore}= require('redux')
const defaultState = {
  counter:0,
}
//类似数组的reduce方法
const reducers = (state=defaultState,action) => {
    switch(action.type){
      case 'increment':
        return {
          //函数传递一个新的状态,原来状态不能改变,所以不能使用state.counter++
          counter:state.counter+1
        }
      default:
        return state
    }
}

const store = createStore(reducers)

//实时监测状态的变化
store.subscribe(()=>{
   console.log(store.getState())
})

store.dispatch(
  {
    type:'increment  '
  }
)

store.dispatch(
  {
    type:'increment'
  }
)

redux实现异步

通过中间件来实现异步操作,在action-creaters和state之间添加一个中间件。

方法一:中间件使用thunk方法
//创建一个仓库
//redux中导入一个,应用中间件的方法
const {
       createStore,
       applyMiddleware
       }= require('redux')



const defaultState = {
  counter:0
} 


//原生事件,需要default
const thunk=require('redux-thunk').default

//纯函数:给一个输入,给一个预期的输出
//类似数组的reduce方法
//给参数state设置一个默认值为defaultState
//reduces方法会自动执行一次
const reducers = (state=defaultState,action) => {
    switch(action.type){
      case 'increment':
        //经过reducers函数返回一个新的状态,需要return
        return {
          //函数传递一个新的状态,原来状态不能改变,所以不能使用state.counter++
          counter:state.counter+1
        }
      case 'loadData':
        return {
          counter:action.data
        } 
      default:
        return state
    }
}

const store = createStore(reducers,applyMiddleware(thunk))

//实时监测状态的变化
store.subscribe(()=>{
   console.log(store.getState())
})

// store.dispatch(
//   {
//     type:'increment'
//   }
// )

//dispatch只能添加一个扁平的对象作为参数,由于加入了中间件所以可以是一个函数,被拦截进行处理,因此可以在这里进行异步请求
//此函数有一个参数,就是我们要使用的dispatch方法的引用
store.dispatch(dispatch=>{
  setTimeout(()=>{
      dispatch({
        type:'loadData',
        data:100
      })
  },3000)
})
thunk 内部实现过程
//thunk原码
function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => (next) => (action) => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

module.exports = thunk;


//原码解析,相当于三层函数的嵌套,相当于以下代码
function createThunkMiddleware(extraArgument) {
  //第一层函数,参数为为store对象,解构出dispatch和getState方法
   return function({ dispatch, getState }) {
       //第二层函数的参数next,相当于dispatch
     return function(next) {
         //第三层函数的参数所提交的action
       return function(action) {
         if (typeof action === 'function') {
           return action(dispatch, getState, extraArgument);
         }
         return next(action)
       }
     }
   }
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

module.exports = thunk;
利用thuck的模式编写redux异步处理的中间件
const myMiddleware = ({ dispatch, getState }) => {
  return (next) => {
    return (action) => {
        //所提交的action
       console.log(action)          
   }
  }
}

module.exports = myMiddleware 
方法二:使用中间件redux-saga
//app.js
const { 
  createStore,
  applyMiddleware
} = require('redux')

const createSagaMiddleware =  require('redux-saga').default
const sagaMiddleware = createSagaMiddleware()

const reducers = require('./reducer')
const store = createStore(reducers, applyMiddleware(sagaMiddleware))

const mySaga=require('./mySaga')
sagaMiddleware.run(mySaga)

store.subscribe(() => {
  console.log(store.getState())
})


store.dispatch({
  type: 'willloadData'
})



//mySaga.js
const {takeEvery,put}=require('redux-saga/effects')

module.exports = function * () {
  yield takeEvery('willloadData', function * () {
     
    let result = yield new Promise((resolve) => {
      setTimeout(() => {
        resolve(1000000)
      },3000)
    })

    yield put({type:'loadData',data: result })
  })
}



//reducers.js
const defaultState = {
  counter: 0
}

// 纯函数
const reducers = (state=defaultState, action) => {
  switch (action.type) {
    case 'increment':
      return {
        counter: state.counter + 1
      }
    case 'loadData':
      return {
        counter: action.data
      }
    default:
      return state
  }
}

module.exports = reducers
状态的拆分(类似vue的模块化)

随着应用变得复杂,需要对 reducer 函数 进行拆分,拆分后的每一块独立负责管理 state 的一部分,combineReducers函数把拆分的多个reduces合并成为一个,人后调用createStore,调用子reducerj将状态合并为一个。

const { combineReducers } = require('redux')
const counter = require('./reducers/counter')
const show = require('./reducers/show')

const reducers = combineReducers({
  counter,
  show
})

module.exports = reducers

合并后的状态

{
    counter:{
        
    }
    show:{
        
    }
}
redux在React中的使用

redux是独立于react的状态管理工具

引入react-redux工具

import React, { Component } from 'react'

//connect 链接store中的state和dispatch方法
//有两个参数,两个参数都是函数,第一个函数的形参是state,第二个参数的形参是dispatch
import { connect } from 'react-redux'
import store from '../redux/counter/store'
//import storeContext from '../context/store_context'

const mapStateToProps = state => ({
    count: state.counter
})

const mapDispatchToProps = dispatch => ({
    increment() {
        dispatch({
            type: 'increment'
        })
    }
})

class Counter extends Component {
    increment = () => {
        this.props.increment()
    }
    render() {

        return (
            <div>
                {this.props.count}
                <button onClick={this.increment}>+</button>
            </div>
        )
    }

}

//connect函数的执行结果是一个高阶组件,传递一个组价作为参数
export default connect(mapStateToProps, mapDispatchToProps)(Counter)
Router(路由)

引入包:react-router-dom

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i7PhD1fS-1583310091046)(C:\Users\yuyang\AppData\Roaming\Typora\typora-user-images\1583225302246.png)]

import  React,{Component} from 'react'
//引入其中的组件
import {
    Route,
    //Switch组件,实现路由匹配的排他性,渲染第一个匹配的组件
    Switch,
    //重定向,放在路由匹配的最下面,防止其他的匹配
    Redirect,
    //Nav的子类,组件类似Router-link,相比Nav可以添加ative-class 
    NavLink
} from 'react-router-dom'
import Movive from './Moive'
import Tv from './Tv'

export default class Index extends Component{
    render(){
        return(
        <div>
            <ul>
                <li>
                    <NavLink to="/movie">电影</NavLink>
                </li>
                <li>
                    <NavLink to="/tv">电视</NavLink>
                </li>
            </ul>
            <Switch>
                <Route
                  path="/tv"
                 exact//也 可以实现精准匹配
                  component={Tv}
                />
                <Route
                  path="/movie"
                  component={Movive}
                />
                <Redirect
                  from="/"
                  to='/movie'
                />
            </Switch>
        </div>
        )
    }
}
//index.js
import React from 'react'
import ReactDom from 'react-dom'

import {BrowserRouter as Router} from 'react-router-dom'
import Index from './pages/router/Index'

ReactDom.render(
    <Router>
        <Index>
        </Index>
    </Router>,
    document.getElementById('root')
)

//Movie.jsx
import React,{Component} from 'react'

export default class Movie extends Component {
    render(){
        return (
            <div>
                Movie
            </div>
    )
   }
}
嵌套路由

在一个组件中,根据路由匹配渲染另一个组件,即实现了路由的嵌套。

import React,{Component} from 'react'
import {
    Route,
    Switch,
    Redirect,
    NavLink
} from 'react-router-dom'
import List from './list'
export default class Movie extends Component {
    render(){
        //props中的match是当前组件的路径
        let {match}=this.props
        console.log(match)
        return (
            <div>
                Movie
                <Route
                  path={match.path+'/list'}
                  component={List}
                />
              
            </div>
    )
   }
}
路由传参
方式一:query的方式,但是根据他在props中的存储方式,使用起来不方便,所以不建议使用query进行传参。
方拾二:动态路由
import React,{Component} from 'react'
import {
    Route,
    Switch,
    Redirect,
    NavLink
} from 'react-router-dom'
import List from './list'
export default class Movie extends Component {
    render(){
        let {match}=this.props
        console.log(this.props)
        return (
            <div>
                //定义一个动态路由
                <NavLink to="/moive/list/2">moive</NavLink>
                <Route
                  path={match.path+'/list/:id'}
                  component={List}
                />
              
            </div>
    )
   }
}

//在list组将的props中可以拿到动态路由

方式二的另一种写法

//在NavLink组件中to是一个对象,
to={{pathname:match.path+'list/2'}}
方式三:state属性传参
import React,{Component} from 'react'
import {
    Route,
    Switch,
    Redirect,
    NavLink
} from 'react-router-dom'
import List from './list'
export default class Movie extends Component {
    render(){
        let {match}=this.props
        console.log(this.props)
        return (
            <div>
              
                <NavLink to={{
                    pathname:match.path+'/list/2',
                    //可以存入props对象中
                    state:{id:2}
                }}>moive</NavLink>
                <Route
                  path={match.path+'/list/:id'}
                  component={List}
                />
              
            </div>
    )
   }
}

//List组建的this.props.location.id中可以拿到传递的参数。
编程式路由
import React,{Component} from 'react'
import TvList from './tvList'
export default class Tv extends Component {
    handleClick=()=>{
        //使用props中history的push方法
        this.props.history.push({pathname:'/moive',state:{id:3}})
    }
    render(){
        return (
            <div>
                tv 
                <button onClick={this.handleClick}>moive</button>
            </div>
    )
   }
}
路由中三种子组件的渲染方式
方式一:最常用最简单的方式component

component中传入的是组件对象的引用,而不是组件的实例。

方式二:render(基于高阶组件的渲染属性),传入一个函数,返回一个组件实例。
<Route
     path="/tv"
     render={(props)=>{
          return (
              //渲染组件实例,传入prop中的对象
              <Tv {...props}/>
                  )
              }}
  />
方式三:children (基于高级组件的渲染属性)

通过match获取路由信息

<Route
                  path="/tv"
                  children={(props)=>{
                      return (
                          <Tv {...props}/>
                      )
                  }}
                />
render和children的区别

children匹配所有的路径

404错误页面的定义
//注意404 页面路由所在的位置,需要放在最下面
import  React,{Component} from 'react'
import {
    Route,
    Switch,
    Redirect,
    NavLink
} from 'react-router-dom'
import Movive from './Moive'
import Tv from './Tv'
import Page404 from './Page404'
export default class Index extends Component{
    render(){
        return(
        <div>
            <ul>
                <li>
                    <NavLink to="/movie">电影</NavLink>
                </li>
                <li>
                    <NavLink to="/tv">电视</NavLink>
                </li>
                  </ul>
            <Switch>
                <Route
                  path="/tv"
                  component={Tv}
                />
                <Route
                  path="/movie"
                  component={Movive}
                />
                <Redirect
                  //精准匹配
                  exact
                  from="/"
                  to='/movie'
                />
                <Route
                  //或使用path=“*”
                  path=""
                  component={Page404}
                />
            </Switch>
        </div>
        )
    }
}
使用地图

百度地图开发平台

  • 申请一个密钥,白名单
  • 使用iframe(因为使用第三方地图必须 在一个页面中嵌入这个页面)
createref

ref.current:当前ref的引用。

Immutable.js
如何在Redux中使用Immutable.js学习资料总结

https://www.cnblogs.com/feiying100/p/7063138.html

https://segmentfault.com/a/1190000010676878?utm_source=tag-newest

immutable的特性
  • 不可变对象

  • 数据共享

seq

seq:一个对象没有map,可以使用seq进行map,是惰性的。

fromJS

把普通对象转化为immutable对象,由于需要遍历整个对象,所以消耗性能。

toJS

不需要解构,

get、set、getIn、setIn 、updateIn
set、get
setIn()、getIn()

深层的设置和获取,传入一个数组作为参数

updateIn()

参数传入一个回调,来进行更新。

range()

取一个范围存入数组。

take()

取几个

immutable与第三方包的结合

如果第三方包不是immutable形式的,

Hooks

https://github.com/happylindz/blog/issues/19

全部使用函数式组件,不在使用类组件。

Hooks的优点
  • 代码的可读性和可维护性变高。
  • 不使用高阶组件、渲染属性、装饰器,使组件的层级变浅
基本使用
export default props => {
    //使用useState()钩子
    //语法糖,底层还是与原来一样
    //useState一个数组,可以解构,解构出的名字可以任意起
    let [count,setCount] = useState(0)
    
    let handleClcik= () => {
        setCount(count+1)
    }
    
    return(
    <div>{count}<button onClick={handleClick}>+</button></div>
    )
}
setCount()
  • 修改状态需要依赖原值的时候,需要回调setCount(()=> {})
  • 不依赖原值,不需要回调
useEffect(参数一:调用后的操作,参数二:那些状态的改变调用此钩子)
  • 相当于componentDidMount()
  • 当不传第二个参数的时候,只要有状态发生变化,就调用;如果传入一个空数组,而其中有依赖的状态,会报错。
  • 有一个return,组件卸载时调用
useContext

实现react中的上下文,即Vue中提供器和注入器。

知识补充

context可以设置默认值,只有不设置provider的时候才会生效,其他时候不生效。

出现的原因?

​ 在函数式的组建中,注入器只能使用Consumer的而不能使用另一种方式,但是Consumer注入的方式支持16.8高版本的react,所以如果项目使用了Hooks,我们知道Hooks需要使用函数式组件,那么引入useContext是很有必要的。

基本使用
const colorContext = React.createContext("gray");
function Bar() {
  const color = useContext(colorContext);
  return <div>{color}</div>;
}
function Foo() {
  return <Bar />;
}
function App() {
  return (
    <colorContext.Provider value={"red"}>
      <Foo />
    </colorContext.Provider>
  );
}
useReducer

实现一个redux

缺点:不支持中间件,不能进行异步操作。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W8lQgbMr-1583310091047)(C:\Users\yuyang\AppData\Roaming\Typora\typora-user-images\1576593996721.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p85gQxWS-1583310091048)(C:\Users\yuyang\AppData\Roaming\Typora\typora-user-images\1576593953063.png)]

useCallback()
出现原因?
//函数式的组件中,没有this,每次使用这个组件,其中定义的变量会被重新赋值,也就是下面的handleClick函数会被重新声明,当此函数传入到子组件中的时候尽管函数的内容没变,但是声明函数存储的地址发生变化,重新渲染子组件
function App() {
  const handleClick = () => {
    console.log('Click happened');
  }
  return <SomeComponent onClick={handleClick}>Click Me</SomeComponent>;
}

可以进行记忆,防止多次调用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2M8ss9au-1583310091049)(C:\Users\yuyang\AppData\Roaming\Typora\typora-user-images\1576566301742.png)]

useMemo

可以用来编写一个缓存组件。

编写一个缓存组件的方法
方法一:使用react.memo(组件),高阶组件
方法二:如果项目使用了Hooks,可以使用useMemo()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9S2UGvTW-1583310091050)(C:\Users\yuyang\AppData\Roaming\Typora\typora-user-images\1576568304912.png)]

方法三:使用pureComponent,如果外部传入的props没有变化,就不进行渲染,实现缓存的效果(存在残缺点)。
方法四 :使用memoization,实现类似vue计算属性的功能。

引入memoize-one包

import memoize from 'memoize-one'
                                                                                          
state={ filterText: "" };

//相当于Vue的计算属性,在 list 或者 filter 变化时,重新运行 filter:
filter = memoize(
	(list,filterText) => list.fliter(item => item.text.include(filterText))
)

render(){
      // 计算最新的过滤后的 list。
    // 如果和上次 render 参数一样,`memoize-one` 会重复使用上一次的值。
     const filteredList=this.filter(this.props.list, this.state.filterText);
    <>
       <input onChange={this.handleChange} value={this.state.filterText}>
           
        <ul>{filteredList.map(item => <li key={item.id}>{item.text}</li>)}</ul>
    </>
}
useRef

函数式组件的Caputer value

函数式组件,中不能难道ref,需要forwradRef(),c此时可以拿到refs.current,但是为undefind,因为没有实现透传,需要使用useImperativeHandle()这个钩子。

自定义Hooks

需要以use开头。

componentWilReceiveProps

protal
React项目
搭建项目的开发环境
  • 用cra(create-react-app)脚手架:yarn add create-react-app 项目名称
  • 用customiz e-cra、react-app-rewired进行脚手架的增强来进行webpack的二次配置
  • 使用react-dom:react-dom则是React剥离出的涉及DOM操作的部分
项目开发的两种方式
  • 以功能进行划分
  • 以角色进行划分
问题一:如果产生一个新页面的路由问题?

​ 把所有的新页面放到一个Router中,作为顶级路由。

问题二:Hooks中使用(useReducer),进行状态管理,不是全局的?

​ useReducer产生的store,只在本组件能够进行修改使用,其他组件会获得初始值,不能获得最新值,

在普通的类组件中没有进行使用,不知道结果如何。

问题三:高阶组件实现的1px边框

​ 通过高阶组件实现的1px边框,只能运用到高阶组件的参数组件上,组件内部的元素不能使用。

问题四:在componentDidmount进行异步请求并且使用setState对state进行修改,报错的问题

​ Warning: Can’t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.

出现原因?

​ 发出异步的请求后数据还没回来,马上切换到其他的组件,此组件立即卸载,当数据请求回来后由于组件已经卸载造成错误。

解决方法

​ 如果使用的是类组件,在componentWillunmount(),组件卸载前的钩子,使用方法终止异步请求;

如果使用了Hooks,在useEffect(),进行return一个回调函数,useEffect()中的回调函数在组件卸载的时候执行。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值