react

307 阅读6分钟

not finished

一、redux

redux是一种JavaScript状态管理器。可与很多类库一起使用。此处介绍与react结合。 redux有三个常用的方法:

import {createStore,applyMiddleware} from 'redux';
import createSagaMiddleware from 'redux-saga';

var sagaMiddle = createSagaMiddle();
var sotre = createStore(reducer,applyMiddleware(sagaMiddle));

sagaMiddleware.run(fun);//saga中间件的实例运行生成函数
//中间键,处理异步的actionredux数据传递的流程

//saga文件  
import {takeEvery,call,put} from 'redux/saga/effets';
//可以监听发出的所有动作
function *test(){
var result = yield call(()=>{
	return fetch(“url”).then((res)=>res.json())
})
console.log(result);
    yield put({
        type:”GETADA”,
        list:result
    })
}
export default function *watchAll(){
	yield takeEvery(‘WATCHALL’,test)
}

运用context将react和redux连接起来

import {Provider} from 'react-redux';
<Rrovider store={store}>
    <Router></Router>
</Provider>
  • reducer,以及如何合并

    reducer是一个纯函数,reducer(state,action)。

    state是只读不改。

    每个模块都有一个reducer,用combineReducers()合并。

  • redux中间件

    中间件是在dispatch和reducer之间的一个应用。

组件需要改变数据的时候store把action传递给reducer,reducer做处理以后会传递给store。

store通过subscribe()调用函数,执行setState使得view视图发生改变

二、 react-router

withRouter

不是通过路由切换过来的组件,没有history,location,match这三个对象

import {withRouter} from 'react-router'
withRouter(App)

react中路由传递参数的方法

动态路由传参数

query传值

react的编程式导航的方法

this.props.history.push("需要跳转的路径")

this.props.history.back()

this.props.history.forward()

this.props.history.replay()

Route的两种渲染方式

<Route path="/home" component={}/>
<Route path="/home" render={()=>{return <Home />}}>

通过render进行组件渲染,优点在于可以进行组件传参,还可以渲染非主组件的标签,缺点在于若使用history ,location,match需要在函数中传递过去???

三、React

类组件和函数组件

生命周期

挂载阶段

  • 1 constructor(props,context)

    初始化:初始化state,将事件处理函数绑定到实例上。

  • 2 static getDerivedStateFromProps(props,state)

    derived state派生状态

    组件实例化后,props更新了调用。若父组件的props更改所带来的的重新渲染,也会触发此方法。

    必须返回一个对象来更新状态或者返回null表示新的props不需要任何state的更新。

    静态方法不能用this,调用是lei.静态方法名()

  • 3 render()

    必需的,当被调用时,将计算this.props和this.state。并返回以下一种类型

    1.React元素。通过jsx创建,可是dom元素,也可是用户自定义的组件

    2.字符串或数字。他们将以文本节点形式渲染到dom中。

    1. null,什么也不渲染。
    2. 布尔值。也是什么都不渲染
    3. 数组:以字符串形式渲染

    注:对象不能直接渲染

  • componentDidMount()

    组件被装配后立即调用。初始化使得dom节点应该进行到这里

    可操作DOM节点。

    通常在这里进行ajax请求。初始化第三方的dom库,

更新节点

  • static getDerivedStateFromProps(props,state)

  • shouldComponentUpdate(nextProps,nextState)

    默认ture,会render。可以加条件减少不必要的渲染,增加性能。

    若返回false,componentWillUpdate、render、componentDidUpdate不会调用

    • PureComponent 进行浅比对,进行性能的优化(纯组件) extends.PureComponent

      参数和返回值都是组件:高阶函数(map,filter,forEach.....)

      仅进行浅层对比,若对象中包含复杂的数据结构,则可能产生错误比对。

      仅在state和props较简单的时候用。

    • 对函数组件用React.memo(组件)

      仅检查props有没改变

      const MyComponent = React.memo(function MyComponent(props) {
        /* 使用 props 渲染 */
      });
      

      默认情况下其只会对复杂对象做浅层对比,如果你想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。

      function MyComponent(props) {
        /* 使用 props 渲染 */
      }
      function areEqual(prevProps, nextProps) {
        /*
        如果把 nextProps 传入 render 方法的返回结果与
        将 prevProps 传入 render 方法的返回结果一致则返回 true,
        否则返回 false
        */
      }
      export default React.memo(MyComponent, areEqual);
      
  • render()

  • getSnapshotBeforeUpdate(prevProps,prevState)

    使组件能够在它们被潜在更改之前捕获当前位置(如滚动位置)

    必须与componentDidUpdate一起用

    必须返回一个值 返回的任何值会作为参数传递给componentDidUpdate()

    不能和旧版的钩子函数一起用

    目的是为了返回数据更新前的dom状态

  • componnetDidUpdate(prevProps,prevState,snapshot)

    将当前props和以前props比较。

    可单独使用

  • componentWillReceiveProps(nextProps)

    当props发生变化时,初始化render时不执行。一般用于父组件状态更新子组件的重新渲染。

    可在子组件的render中获取最新的props,更新子组件的state。可将子组件的数据处理及接口在这里执行,而不用都放在父组件中。于是改请求只会在该组件渲染时才发出,减少了请求的负担。

卸载阶段

  • componentWillUnmount()

    组件被卸载并销毁之前被调用。

    清理:定时器无效,取消网络请求、清理在componentDidMount中创建的任何监听

  • 错误处理

    • static getDerivedStateFromError()
    • componentDidCatch()

11 Props默认值,限定类型

设置props默认值:调用this.props

defaultProps用于确保this.props.key在父组件没有指定其值的时,有一个默认值。

类组件

//类组件
static defaultProps = {
    key:默认值
}
//无状态组件
组件名.defaultProps={
    key:默认值
}

props限定类型

propTypes类型检查发生在defaultProps赋值后,所以类型检查也使用于defaultProps

//类组件
import PropTypes from 'prop-types'
static propTypes = {
    key:PropTypes.类型
    name: React.PropTypes.string.isRequired
}
//无状态组件
组件名.propTypes={
    key.propTypes.类型.isRequired(必须传)
    data: PropTypes.object.isRequired
}

createProtal(childrem,domNode,key)

不挂载在父组件下,挂在任意dom上。常见场景:弹窗

import { createProtal } from 'react-dom'

<div>
    <p>这个子节点被放置在父节点div中</p>
    {createPortal(
      <p>这个子节点被放置在document body中</p>,
      document.body
    )}
</div>

setState

setState({},callback)

//wrong
this.setState({
    counter:this.state.counter+this.props.increment
},callback);
//correct
this.setState((prevState,props)=>{
    counter:prevState.counter+props.increment
},callback)

this.setState({key:新的value},()=>{回调函数}) 连续多个对象参数会合并,以最后一个为准, 连续执行多次,放入队列中一次执行

callback用来验证数据是否修改成功,同时可以获取到数据更新后的DOM结构,同componentDidMount

高阶组件

参数和返回值都是组件。

作用:

  • 属性代理——进行组件的复用(比如算积分)
  • 反向集成——对渲染的劫持(比如购物车组件没有登录就不能渲染)

常用的hook

useState

useRef

  • 绑定dom元素
  • 绑定值,当该值变化的时候,不会触发重新渲染。
const intervlRef = useRef(0)
function handleClick = () => {
    intervlRef.current = ref.current +1 // 不会重新渲染render
}
console.log('intervalRef.current', intervalRef.current) // 始终是初始值

useEffect

useEffectEvent

useLayoutEffect

在浏览器重新绘制屏幕之前就触发了

useImperativeHandle

useCallback

useMemo

useID

useContext

useInsertionEffect

在react中解决单页面开发首次加载白屏现象

  • 路由懒加载方式:react-loadable
  • 首屏服务端渲染

react中key的理解

diff算法是比较同级元素。

react用key识别组件。

key值相同,若属性有变化,则更新组件对用的属性。没有变化,就不需要更新

key值不同,则先销毁该组件,然后创建该组件。

对context的理解

组件传值是通过props传递的,不能跨组件传递,若要跨组件则可用context。

子孙组件就可调用store

其他

  • 只要父组件重新渲染, 即使子组件的props未变化,子组件也会重新渲染,触发render。
  • Diff算法。Virtual Dom 虚拟dom。
  • React基于虚拟DOM和diff算法,以及性能很好了,但依旧可以配合shouldComponentUpdate和PureComponent使用。React.memo()
  • 强制更新DOM,this.foreUpdate()