react学习总结

60 阅读8分钟

react中文官网:react.docschina.org/

(一)组件化优点

1.增强代码重用性,提高开发效率;
2.简化调试步骤,提升整个项目的可维护性;
3.便于协同开发;
4.注意点:降低耦合性

(二)组件通信

在一个典型的 React 应⽤用中,数据是通过 props 属性⾃自上⽽而下(由⽗父及⼦子)进⾏行行传递的,但这种做法对于某些类型的属性⽽而⾔言是极其繁琐的(例例如:地区偏好,UI 主题),这些属性是应⽤用程序中许多组件都 需要的。Context 提供了了⼀一种在组件之间共享此类值的方式,而不不必显式地通过组件树的逐层传递 props。 React中使⽤用Context实现祖代组件向后代组件跨层级传值。Vue中的provide & inject来源于Context。

Context API

1.React.createContext
创建⼀一个 Context 对象。当 React 渲染一个订阅了了这个 Context 对象的组件,这个组件会从组件树中离 ⾃自身最近的那个匹配的 Provider 中读取到当前的 context 值。

2.Context.Provider
Provider 接收⼀一个 value 属性,传递给消费组件,允许消费组件订阅 context 的变化。⼀一个 Provider 可以和多个消费组件有对应关系。多个 Provider 也可以嵌套使⽤用,⾥里里层的会覆盖外层的数据。 当 Provider 的 value 值发⽣生变化时,它内部的所有消费组件都会重新渲染。Provider 及其内部 consumer 组件都不不受制于 shouldComponentUpdate 函数,因此当 consumer 组件在其祖先组件退 出更更新的情况下也能更更新.

3.Class.contextType(注意:只通过改API订阅单一的context)
挂载在 class 上的 contextType 属性会被重赋值为一个由 React.createContext() 创建的 Context 对象。这能让你使⽤用 this.context 来消费最近 Context 上的那个值。你可以在任何⽣生命周期中访问 到它,包括 render 函数中。

4.Context.Consumer
这个函数接收当前的 context 值,返回⼀一个 React 节点。传递给函数的 value 值等同于往上组件树离 这个 context 最近的 Provider 提供的 value 值。如果没有对应的 Provider, value 参数等同于传递 给 createContext() 的 defaultValue

5.useContext
接收一个 context 对象( React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定。只能⽤用 在function组件中。

使用context

context.js创建context image.png

Context.Provider

image.png

Context.Consumer

image.png

Class.contextType

image.png

useContext

image.png

(三)Redux

官网:www.redux.org.cn 函数式编程倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂运算。函数式编程有2个最基本的运算:合成和柯里化。
合成(compose):
如果一个值要经过多个函数,才能变成另外加一个值,就可以把所有中间步骤合成一个函数,这叫做函数的合成。合成的好处显而易见,他让代码变得简单而且富有可读性,同时通过不同的 组合方式,我们可以轻易组合出其他常用函数,让我们的代码更具表现力。

image.png 柯里化:
是把接受多个参数的函数变换成接受一个单一参数的函数,并且返回接受余下的参数而且返回结果的新函数的技术

image.png

Reducer就是一个纯函数,接受旧的state和action,返回新的state.永远不要在reducer里做这些操作:
1.修改传入的参数;
2.执行有副作用的操作,如API请求和路由跳转;
3.调用非纯函数,如Date.now()或Math.random().

image.png

创建store

image.png

使用

image.png

源码: createStore

image.png

applyMiddleware.js

image.png

(四)Hooks API

useState

image.png initialState 参数只会在组件的初始渲染中起作用,后续渲染时会被忽略。如果初始 state 需要通过复杂计算获得,则可以传入一个函数,在函数中计算并返回初始的 state,此函数只在初始渲染时被调用:

image.png

useEffect

该 Hook 接收一个包含命令式、且可能有副作用代码的函数。 在函数组件主体内(这里指在 React 渲染阶段)改变 DOM、添加订阅、设置定时器、记录日志以及执行其他包含副作用的操作都是不被允许的,因为这可能会产生莫名其妙的 bug 并破坏 UI 的一致性.

通常,组件卸载时需要清除 effect 创建的诸如订阅或计时器 ID 等资源。要实现这一点,useEffect 函数需返回一个清除函数。以下就是一个创建订阅的例子:

image.png

执行时机:componentDidMountcomponentDidUpdate 、componentWillUnmount.
与 componentDidMountcomponentDidUpdate 不同的是,在浏览器完成布局与绘制之后,传给 useEffect 的函数会延迟调用。这使得它适用于许多常见的副作用场景,比如设置订阅和事件处理等情况,因此不应在函数中执行阻塞浏览器更新屏幕的操作。

默认情况下,effect 会在每轮组件渲染完成后执行。这样的话,一旦 effect 的依赖发生变化,它就会被重新创建。 可以给 useEffect 传递第二个参数,实现改参数改变时,才会触发执行

useContext
接收一个 context 对象(React.createContext 的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider> 的 value prop 决定。

useReducer
useState的替代方案。它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法。

image.png

useCallback
把内联回调函数及依赖项数组作为参数传入 useCallback,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子组件时,它将非常有用。 useCallback(fn, deps) 相当于 useMemo(() => fn, deps)

image.png

useMemo

image.png 把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。

记住,传入 useMemo 的函数会在渲染期间执行。请不要在这个函数内部执行与渲染无关的操作,诸如副作用这类的操作属于 useEffect 的适用范畴,而不是 useMemo

如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值。

useRef

image.png useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。

useImperativeHandle
useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值。在大多数情况下,应当避免使用 ref 这样的命令式代码。useImperativeHandle 应当与 forwardRef 一起使用:

image.png

在本例中,渲染 <FancyInput ref={inputRef} /> 的父组件可以调用 inputRef.current.focus()

useLayoutEffect
其函数签名与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用 effect。可以使用它来读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。

尽可能使用标准的 useEffect 以避免阻塞视觉更新。

(五)react-redux

1.提供两个api:
Provider为后代组件提供store;
connect为组件提供数据和变更的方法。

<Provider store>

connect([mapStateToProps], [mapDispatchToProps], [mergeProps],

[options])

image.png

image.png

实现react-redux

image.png

image.png

注意: 如果前后两次的值相同, useState 和 useReducer Hook 都会放弃更新。原地修改 state 并调 用 setState 不会引起重新渲染。 通常,你不应该在 React 中修改本地 state。然而,作为一条出路,你可以用一个增长的计数器来 在 state 没变的时候依然强制一次重新渲染:

image.png

(六)react-redux hooks API
1.useSelector 获取store state;
2.useDispatch获取dispatch

image.png

实现hooks:

image.png

(六)react-router react-router包含3个库,react-router、react-router-dom和react-router-native。react-router提供 最基本的路由功能,实际使用的时候我们不会直接安装react-router,而是根据应用运行的环境选择安 装react-router-dom(在浏览器中使用)或react-router-native(在rn中使用)。react-router-dom和 react-router-native都依赖react-router,所以在安装时,react-router也会自动安装,创建web应用, 使用

react-router中奉行一切皆组件的思想,路由器-Router、链接-Link、路由-Route、独占-Switch、重 定向-Redirect都以组件形式存在

Route渲染优先级:children>component>render。 三者能接收到同样的[route props],包括match, location and history,但是当不匹配的时候, children的match为null。 这三种方式互斥,你只能用一种。

children:func
有时候,不管location是否匹配,你都需要渲染一些内容,这时候你可以用children。 除了不管location是否匹配都会被渲染之外,其它工作方法与render完全一样。

render:func
但是当你用render的时候,你调用的只是个函数。但是它和component一样,能访问到所有的[route props]。

component: component
只在当location匹配的时候渲染。

当你用 component 的时候,Route会用你指定的组件和React.createElement创建一个新的[React element]。这意味着当你提供的是一个内联函数的时候,每次render都会创建一个新的组件。这会导 致不再更新已经现有组件,而是直接卸载然后再去挂载一个新的组件。因此,当用到内联函数的内联渲 染时,请使用render或者children。

**router hooks API **

1.useRouteMatch,
2.useHistory,
3.useLocation,
4.useParams