阅读react-redux源码(四) - connectAdvanced、wrapWithConnect、ConnectFunction和checkForUpdates

  • 阅读react-redux源码 - 零
  • 阅读react-redux源码 - 一
  • 阅读react-redux源码(二) - createConnect、match函数的实现
  • 阅读react-redux源码(三) - mapStateToPropsFactories、mapDispatchToPropsFactories和mergePropsFactories
  • 阅读react-redux源码(四) - connectAdvanced、wrapWithConnect、ConnectFunction和checkForUpdates

终于到了最核心的connectAdvanced.js文件,在这里做的最主要的事情就是响应Provider提供的store的改变。除了响应store的变化,还做了很多事情,分别是:ref的处理,是否是pure模式,还有对于store改变的事件的转发。

首先回顾下connectAdvanced函数在connect.js中是如何被使用的。

return connectHOC(selectorFactory, {// used in error messagesmethodName: 'connect',// used to compute Connect's displayName from the wrapped component's displayName.getDisplayName: name => `Connect(${name})`,// if mapStateToProps is falsy, the Connect component doesn't subscribe to store state changesshouldHandleStateChanges: Boolean(mapStateToProps),// passed through to selectorFactoryinitMapStateToProps,initMapDispatchToProps,initMergeProps,pure,areStatesEqual,areOwnPropsEqual,areStatePropsEqual,areMergedPropsEqual,// any extra options args can override defaults of connect or connectAdvanced...extraOptions
})

connect函数调用后返回connectHOC调用后的返回值

而connect函数是这样用的:

connect(mapStateToProps, mapDispatchToProps)(wrappedComponent)

connect的返回值就是connectHOC的返回值,所以返回值一定也是一个方法。connectHOCReturnValue(wrappedComponent)

connectAdvanced

继续来看connectAdvanced.js文件中connectAdvanced方法的实现。因为整个方法的实现异常复杂,所以我决定分开叙述,以功能点的方式进行,首先最重要的当然是如何响应store中的变化

function connectAdvanced (selectorFactory,{// the func used to compute this HOC's displayName from the wrapped component's displayName.// probably overridden by wrapper functions such as connect()getDisplayName = name => `ConnectAdvanced(${name})`,// shown in error messages// probably overridden by wrapper functions such as connect()methodName = 'connectAdvanced',// REMOVED: if defined, the name of the property passed to the wrapped element indicating the number of// calls to render. useful for watching in react devtools for unnecessary re-renders.renderCountProp = undefined,// determines whether this HOC subscribes to store changesshouldHandleStateChanges = true,// REMOVED: the key of props/context to get the storestoreKey = 'store',// REMOVED: expose the wrapped component via refswithRef = false,// use React's forwardRef to expose a ref of the wrapped componentforwardRef = false,// the context consumer to usecontext = ReactReduxContext,// additional options are passed through to the selectorFactory...connectOptions} = {}
) {...return function wrapWithConnect(WrappedComponent) {...}
}

wrapWithConnect函数就是connectAdvanced函数的返回值,也就是 connect(mapStateToProps, mapDispatchToProps)的返回值,入参WrappedComponent就是我们的业务组件(需要连接到store的组件)。

wrapWithConnect

return function wrapWithConnect(WrappedComponent) {...const selectorFactoryOptions = {...connectOptions,getDisplayName,methodName,renderCountProp,shouldHandleStateChanges,storeKey,displayName,wrappedComponentName,WrappedComponent}...function createChildSelector(store) {return selectorFactory(store.dispatch, selectorFactoryOptions)}...function ConnectFunction(props) {...}const Connect = pure ? React.memo(ConnectFunction) : ConnectFunction...return hoistStatics(Connect, WrappedComponent)
}

函数wrapWithConnect的入参是我们的业务组件,返回值是一个内部组件 Connect,return hoistStatics(Connect, WrappedComponent)hoistStatics函数主要作用是复制函数的静态属性,本例中是将WrappedComponent的静态属性复制到Connect组件上(Connect就是 ConnectFunction)。

核心中的核心 ConnectFunction 函数

通过其大写的首字母就知道是一个React组件。这个组件就是真正被导出的组件。看看是怎么实现的,如何连接到store的。

function ConnectFunction(props) {...const contextValue = useContext(ContextToUse)...const store = didStoreComeFromProps ? props.store : contextValue.store...const childPropsSelector = useMemo(() => {// The child props selector needs the store reference as an input.// Re-create this selector whenever the store changes.return createChildSelector(store)}, [store])...const [subscription, notifyNestedSubs] = useMemo(() => {if (!shouldHandleStateChanges) return NO_SUBSCRIPTION_ARRAY// This Subscription's source should match where store came from: props vs. context. A component// connected to the store via props shouldn't use subscription from context, or vice versa.const subscription = new Subscription(store,didStoreComeFromProps ? null : contextValue.subscription)// `notifyNestedSubs` is duplicated to handle the case where the component is unmounted in// the middle of the notification loop, where `subscription` will then be null. This can// probably be avoided if Subscription's listeners logic is changed to not call listeners// that have been unsubscribed in the  middle of the notification loop.const notifyNestedSubs = subscription.notifyNestedSubs.bind(subscription)return [subscription, notifyNestedSubs]}, [store, didStoreComeFromProps, contextValue])...const [[previousStateUpdateResult],forceComponentUpdateDispatch] = useReducer(storeStateUpdatesReducer, EMPTY_ARRAY, initStateUpdates)if (previousStateUpdateResult && previousStateUpdateResult.error) {throw previousStateUpdateResult.error}// Set up refs to coordinate values between the subscription effect and the render logicconst lastChildProps = useRef()const lastWrapperProps = useRef(wrapperProps)const childPropsFromStoreUpdate = useRef()const renderIsScheduled = useRef(false)const actualChildProps = usePureOnlyMemo(() => {// Tricky logic here:// - This render may have been triggered by a Redux store update that produced new child props// - However, we may have gotten new wrapper props after that// If we have new child props, and the same wrapper props, we know we should use the new child props as-is.// But, if we have new wrapper props, those might change the child props, so we have to recalculate things.// So, we'll use the child props from store update only if the wrapper props are the same as last time.if (childPropsFromStoreUpdate.current &&wrapperProps === lastWrapperProps.current) {return childPropsFromStoreUpdate.current}// TODO We're reading the store directly in render() here. Bad idea?// This will likely cause Bad Things (TM) to happen in Concurrent Mode.// Note that we do this because on renders _not_ caused by store updates, we need the latest store state// to determine what the child props should be.return childPropsSelector(store.getState(), wrapperProps)}, [store, previousStateUpdateResult, wrapperProps])// We need this to execute synchronously every time we re-render. However, React warns// about useLayoutEffect in SSR, so we try to detect environment and fall back to// just useEffect instead to avoid the warning, since neither will run anyway.useIsomorphicLayoutEffectWithArgs(captureWrapperProps, [lastWrapperProps,lastChildProps,renderIsScheduled,wrapperProps,actualChildProps,childPropsFromStoreUpdate,notifyNestedSubs])// Our re-subscribe logic only runs when the store/subscription setup changesuseIsomorphicLayoutEffectWithArgs(subscribeUpdates,[shouldHandleStateChanges,store,subscription,childPropsSelector,lastWrapperProps,lastChildProps,renderIsScheduled,childPropsFromStoreUpdate,notifyNestedSubs,forceComponentUpdateDispatch],[store, subscription, childPropsSelector])// Now that all that's done, we can finally try to actually render the child component.// We memoize the elements for the rendered child component as an optimization.const renderedWrappedComponent = useMemo(() => <WrappedComponent {...actualChildProps} ref={forwardedRef} />,[forwardedRef, WrappedComponent, actualChildProps])// If React sees the exact same element reference as last time, it bails out of re-rendering// that child, same as if it was wrapped in React.memo() or returned false from shouldComponentUpdate.const renderedChild = useMemo(() => {if (shouldHandleStateChanges) {// If this component is subscribed to store updates, we need to pass its own// subscription instance down to our descendants. That means rendering the same// Context instance, and putting a different value into the context.return (<ContextToUse.Provider value={overriddenContextValue}>{renderedWrappedComponent}</ContextToUse.Provider>)}return renderedWrappedComponent}, [ContextToUse, renderedWrappedComponent, overriddenContextValue])return renderedChild
}

首先从contextValue中取出store。然后拿到childPropsSelector(用于计算正真需要注入业务组件的完整props),该函数通过store.getState()wrapperProps来计算出新的actualChildProps用于渲染子组件。

再往下看得到了[subscription, notifyNestedSubs]这两个名字应该很熟悉了在阅读react-redux源码 - 一中有详细的介绍。这里的subscripion也是一个事件对象,而notifyNestedSubs可以通知subscription的所有监听者,事件发生,执行回调。

const subscription = new Subscription(store,didStoreComeFromProps ? null : contextValue.subscription
)

这里的subscription监听了contextValue.subscription的变化,或者store的变化(这里后面详细介绍)。

const [[previousStateUpdateResult],forceComponentUpdateDispatch
] = useReducer(storeStateUpdatesReducer, EMPTY_ARRAY, initStateUpdates)

这个是引起组件 ConnectFunction更新的关键,只有调用forceComponentUpdateDispatch函数,组件ConnectFunction才会更新。

storeStateUpdatesReducer

function storeStateUpdatesReducer(state, action) {const [, updateCount] = statereturn [action.payload, updateCount]
}

storeStateUpdatesReducer直接返回一个数组,第一项就是dispatch的action的payload,也就是说 forceComponentUpdateDispatch 入参的payload属性是什么那么previousStateUpdateResult值就是什么。

如果previousStateUpdateResult.error有值表示发生错误,直接抛出去,不要继续了。

if (previousStateUpdateResult && previousStateUpdateResult.error) {throw previousStateUpdateResult.error
}

下面定义了几个ref:

const lastChildProps = useRef()
const lastWrapperProps = useRef(wrapperProps)
const childPropsFromStoreUpdate = useRef()
const renderIsScheduled = useRef(false)

lastChildProps:最后的childProps(传递给WrappedComponent的props,这里记录的是上一次的props)

lastWrapperProps:父元素传递进来的props

childPropsFromStoreUpdate:store更新计算出来的childProps

renderIsScheduled:是否在render中

下面开始计算真实的childProps也就是actualChildProps值:

const actualChildProps = usePureOnlyMemo(() => {// Tricky logic here:// - This render may have been triggered by a Redux store update that produced new child props// - However, we may have gotten new wrapper props after that// If we have new child props, and the same wrapper props, we know we should use the new child props as-is.// But, if we have new wrapper props, those might change the child props, so we have to recalculate things.// So, we'll use the child props from store update only if the wrapper props are the same as last time.if (childPropsFromStoreUpdate.current &&wrapperProps === lastWrapperProps.current) {return childPropsFromStoreUpdate.current}// TODO We're reading the store directly in render() here. Bad idea?// This will likely cause Bad Things (TM) to happen in Concurrent Mode.// Note that we do this because on renders _not_ caused by store updates, we need the latest store state// to determine what the child props should be.return childPropsSelector(store.getState(), wrapperProps)
}, [store, previousStateUpdateResult, wrapperProps])

首先查看是否是store变动引起的更新,如果是,还需要查来自父元素的props是否没有更新过,如果是,则直接返回store更新计算出来的childProps,否则弃用store更新计算出来的childProps(childPropsFromStoreUpdate.current)重新通过childPropsSelector(store.getState(), wrapperProps)计算childProps。

 useIsomorphicLayoutEffectWithArgs(captureWrapperProps, [lastWrapperProps,lastChildProps,renderIsScheduled,wrapperProps,actualChildProps,childPropsFromStoreUpdate,notifyNestedSubs])

这个其实就是在缓存数据,为了缓存本轮更新的值,在下一次更新的时候可以拿到现在的值。

captureWrapperProps

function captureWrapperProps(lastWrapperProps,lastChildProps,renderIsScheduled,wrapperProps,actualChildProps,childPropsFromStoreUpdate,notifyNestedSubs
) {// We want to capture the wrapper props and child props we used for later comparisonslastWrapperProps.current = wrapperPropslastChildProps.current = actualChildPropsrenderIsScheduled.current = false// If the render was from a store update, clear out that reference and cascade the subscriber updateif (childPropsFromStoreUpdate.current) {childPropsFromStoreUpdate.current = nullnotifyNestedSubs()}
}

这里做了两件事情,一个是缓存了wrapperProps值,actualChildProps值和将是否在渲染重置为false。第二个是检查是否是store变更引起的更新,如果是则通知subscription的订阅者需要拉取最新的state。

在往下就实现了订阅更新了,关联起上面的subscription实例和上面提到的更新组件的唯一方法 forceComponentUpdateDispatch

function subscribeUpdates(shouldHandleStateChanges,store,subscription,childPropsSelector,lastWrapperProps,lastChildProps,renderIsScheduled,childPropsFromStoreUpdate,notifyNestedSubs,forceComponentUpdateDispatch
) {// If we're not subscribed to the store, nothing to do hereif (!shouldHandleStateChanges) return// Capture values for checking if and when this component unmountslet didUnsubscribe = falselet lastThrownError = null// We'll run this callback every time a store subscription update propagates to this componentconst checkForUpdates = () => {if (didUnsubscribe) {// Don't run stale listeners.// Redux doesn't guarantee unsubscriptions happen until next dispatch.return}const latestStoreState = store.getState()let newChildProps, errortry {// Actually run the selector with the most recent store state and wrapper props// to determine what the child props should benewChildProps = childPropsSelector(latestStoreState,lastWrapperProps.current)} catch (e) {error = elastThrownError = e}if (!error) {lastThrownError = null}// If the child props haven't changed, nothing to do here - cascade the subscription updateif (newChildProps === lastChildProps.current) {if (!renderIsScheduled.current) {notifyNestedSubs()}} else {// Save references to the new child props.  Note that we track the "child props from store update"// as a ref instead of a useState/useReducer because we need a way to determine if that value has// been processed.  If this went into useState/useReducer, we couldn't clear out the value without// forcing another re-render, which we don't want.lastChildProps.current = newChildPropschildPropsFromStoreUpdate.current = newChildPropsrenderIsScheduled.current = true// If the child props _did_ change (or we caught an error), this wrapper component needs to re-renderforceComponentUpdateDispatch({type: 'STORE_UPDATED',payload: {error}})}}// Actually subscribe to the nearest connected ancestor (or store)subscription.onStateChange = checkForUpdatessubscription.trySubscribe()// Pull data from the store after first render in case the store has// changed since we began.checkForUpdates()const unsubscribeWrapper = () => {didUnsubscribe = truesubscription.tryUnsubscribe()subscription.onStateChange = nullif (lastThrownError) {// It's possible that we caught an error due to a bad mapState function, but the// parent re-rendered without this component and we're about to unmount.// This shouldn't happen as long as we do top-down subscriptions correctly, but// if we ever do those wrong, this throw will surface the error in our tests.// In that case, throw the error from here so it doesn't get lost.throw lastThrownError}}return unsubscribeWrapper
}

这个函数里主要是将 subscription 的change关联到forceComponentUpdateDispatch上,实现方式如下:

subscription.onStateChange = checkForUpdates
subscription.trySubscribe()checkForUpdates()

checkForUpdates

首先根据最新的state和最新的wrapperProps来计算出newChildProps,如果计算出来的childProps和上一次的childProps一样,那么当前组件不必更新。但是当组件不需要更新的时候则需要单独通知subscription的监听者,state是有更新的,因为每个组件监听的state是不一样的,虽然当前组件没有更新,但是别的组件会获取到新的state用以更新。

如果不一样则需要更新:

lastChildProps.current = newChildProps
childPropsFromStoreUpdate.current = newChildProps
renderIsScheduled.current = trueforceComponentUpdateDispatch({type: 'STORE_UPDATED',payload: {error}
})

需要更新当前组件需要调用方法forceComponentUpdateDispatch,并且设置缓存上lastChildProps.current = newChildPropschildPropsFromStoreUpdate.current = newChildProps,其中childPropsFromStoreUpdate.current会在 forceComponentUpdateDispatch一起的下一次更新时候通知captureWrapperProps函数需要notifyNestedSubs,通知subscription对象有state更新。

到这里说完了store更新的流程:store更新会触发subscription的onStateChange也就是上面说的checkForUpdates方法,该方法会检查当前组件订阅的state和wrapperProps生成的childProps是否改变了,如果改变需要通知更新当前组件,如果没有改变需要通知自己的订阅者有新的state产生。

#wrapperProps更新引起的组件更新

const actualChildProps = usePureOnlyMemo(() => {if (childPropsFromStoreUpdate.current &&wrapperProps === lastWrapperProps.current) {return childPropsFromStoreUpdate.current}return childPropsSelector(store.getState(), wrapperProps)
}, [store, previousStateUpdateResult, wrapperProps])

父组件传入的props更新的话会重新计算actualChildProps,然后传给组件WrappedComponent。

单独由父组件传入的props更新导致的组件更新,childPropsFromStoreUpdate.current 值一定为假所以执行的是 childPropsSelector(store.getState(), wrapperProps)计算新的 actualChildProps

当然wrapperProps的更新还会执行函数captureWrapperProps来捕获新的值,用于下次对比。

renderIsScheduled

这个标识符表示的是否在更新中,我们知道react的update是“异步”的,所以当连续多次dispatch的时候:

newChildProps === lastChildProps.current这个等式可能会多次成立(dispatch(1); dispatch(1);)。如果没有 !renderIsScheduled.current控制会导致 notifyNestedSubs()多次执行,这是不必要的,因为后面的:

function captureWrapperProps() {...if (childPropsFromStoreUpdate.current) {childPropsFromStoreUpdate.current = nullnotifyNestedSubs()}...}

更新结束后会一次性通知有state改变。

继续往下看:

function ConnectFunction(props) {...const renderedWrappedComponent = useMemo(() => <WrappedComponent {...actualChildProps} ref={forwardedRef} />,[forwardedRef, WrappedComponent, actualChildProps])const renderedChild = useMemo(() => {if (shouldHandleStateChanges) {// If this component is subscribed to store updates, we need to pass its own// subscription instance down to our descendants. That means rendering the same// Context instance, and putting a different value into the context.return (<ContextToUse.Provider value={overriddenContextValue}>{renderedWrappedComponent}</ContextToUse.Provider>)}return renderedWrappedComponent}, [ContextToUse, renderedWrappedComponent, overriddenContextValue])return renderedChild
}

ConnectFunction组件最后返回了组件renderedChild,而该组件则是renderedWrappedComponent是一个被缓存的组件:<WrappedComponent {...actualChildProps} ref={forwardedRef} />可以看出来actualChildProps这个计算出来的总属性被注入给了我们的业务组件。

以上就是从订阅store更新以更新组件自身的角度看了函数connectAdvanced,接下来将从生下的角度查看该函数做的事情。

  • 阅读react-redux源码 - 零
  • 阅读react-redux源码 - 一
  • 阅读react-redux源码(二) - createConnect、match函数的实现
  • 阅读react-redux源码(三) - mapStateToPropsFactories、mapDispatchToPropsFactories和mergePropsFactories
  • 阅读react-redux源码(四) - connectAdvanced、wrapWithConnect、ConnectFunction和checkForUpdates

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/361999.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(转)模拟鼠标/键盘

鼠标操作类 using System;namespace Edobnet.Net.Lib{/// <summary>/// Mouse 的摘要说明。/// </summary>public class Mouse{public Mouse(){//// TODO: 在此处添加构造函数逻辑//}internal const byte SM_MOUSEPRESENT 19;internal const byte SM_CMOUSEBUTTON…

c++ 返回 char*

一段在C里经常犯错误的代码 一个类&#xff1a; class C{public:C(){}~C(){}public:string a;string funa(){string tmp "1234";return tmp;}};外部调用类C并使用其成员&#xff1a; C classc;char *test1 classc.a.c_str();printf("%s\n", test1);上述正…

JSF的工作方式和调试方式–可以使用polyglot吗?

JSF不是我们通常认为的那样。 这也是一个调试起来可能有些棘手的框架&#xff0c;尤其是在初次遇到时。 在这篇文章中&#xff0c;让我们继续探讨为什么会出现这种情况&#xff0c;并提供一些JSF调试技术。 我们将讨论以下主题&#xff1a; JSF不是我们经常想到的 JSF调试的难…

React组件实现越级传递属性

如果有这样一个结构&#xff1a;三级嵌套&#xff0c;分别是&#xff1a;一级父组件、二级子组件、三级孙子组件&#xff0c;且前者包含后者&#xff0c;结构如图&#xff1a; 如果把一个属性&#xff0c;比如color&#xff0c;从一级传递给三级&#xff0c;一般做法是使用prop…

尝试Office 2003 VSTO的开发、部署

背景&#xff1a;一年前&#xff0c;某项目需要使用到Excel进行数据录入&#xff0c;考虑到很多用户还是使用XPOffice 2003&#xff0c;所以开发的时候直接使用Excel 2003版本进行VBA开发。也许很多人都会说&#xff0c;Win10都出了&#xff0c;微软的Office都要免费了&#xf…

阅读react-redux源码(五) - connectAdvanced中store改变的事件转发、ref的处理和pure模式的处理

阅读react-redux源码 - 零阅读react-redux源码 - 一阅读react-redux源码(二) - createConnect、match函数的实现阅读react-redux源码(三) - mapStateToPropsFactories、mapDispatchToPropsFactories和mergePropsFactories阅读react-redux源码(四) - connectAdvanced、wrapWithC…

Servlet编程API

一、基本的servlet APIJavaEE关于Servlet的API主要有两个包&#xff1a;javax.servlet和javax.servlet.http。前者主要提供了Web容器能够使用的servlet基本类和接口&#xff0c;后者主要包括和HTTP协议相关的servlet类和接口。对servlet的编程&#xff0c;主要是根据需要&#…

初级开发人员在编写单元测试时常犯的错误

自从我编写第一个单元测试以来已经有10年了。 从那时起&#xff0c;我不记得我已经编写了成千上万的单元测试。 老实说&#xff0c;我在源代码和测试代码之间没有任何区别。 对我来说是同一回事。 测试代码是源代码的一部分。 在过去的3-4年中&#xff0c;我与多个开发团队合作…

OpenDaylight开发hello-world项目之开发工具安装

OpenDaylight开发hello-world项目之开发环境搭建 OpenDaylight开发hello-world项目之开发工具安装 OpenDaylight开发hello-world项目之代码框架搭建 在ODL开发之前&#xff0c;要安装好开发环境。ODL使用java语言开发&#xff0c;所以要安装好java。ODL的代码框架是有maven这个…

Google Chrome 扩展程序开发

根据公司的规定&#xff0c;每月八小时&#xff0c;弹性工作制。所以大家平时来的不太准时&#xff0c;如果有事&#xff0c;下班也就早些回去了。所以一个月下来工作时间可能不够&#xff0c;但是公司的考勤日历是这样的&#xff1a; 除了请假和法定节假日外&#xff0c;其他样…

阅读react-redux源码(六) - selectorFactory处理store更新

阅读react-redux源码 - 零阅读react-redux源码 - 一阅读react-redux源码(二) - createConnect、match函数的实现阅读react-redux源码(三) - mapStateToPropsFactories、mapDispatchToPropsFactories和mergePropsFactories阅读react-redux源码(四) - connectAdvanced、wrapWithC…

[Silverlight入门系列]使用MVVM模式(7):ViewModel的INotifyPropertyChanged接口实现

本文说说ViewModel的这个INotifyPropertyChanged接口可以用来做啥&#xff1f; 举例1&#xff1a;我有个TabControl&#xff0c;里面放了很多View&#xff0c;每个由ViewModel控制&#xff0c;我想是想TabSelectionChanged就打开相应的ViewModel&#xff0c;怎么做&#xff1f;…

无状态Spring安全性第1部分:无状态CSRF保护

如今&#xff0c;随着RESTful架构变得越来越标准&#xff0c;可能值得花一些时间重新考虑当前的安全方法。 在这个小系列的博客文章中&#xff0c;我们将探索一些以无状态方式解决与Web相关的安全问题的相对较新的方法。 这第一篇文章是关于保护您的网站免受跨站请求伪造&#…

window.Event参数详解

原文地址&#xff1a;window.Event参数详解作者&#xff1a;cz0090704window.evet 说明 event代表事件的状态&#xff0c;例如触发event对象的元素、鼠标的位置及状态、按下的键等等。 event对象只在事件发生的过程中才有效。 event的某些属性只对特定的事件有意义。比如&…

微信群运营之设计运营思路

商家要想运营好微信群&#xff0c;那么首要做的工作就是设计运营思路。如果做事毫无章法思路&#xff0c;那么很有可能会让自己的工作陷入僵局。运营微信群并不简单&#xff0c;需要考虑多方面社群鸭因素。卖什么产品&#xff0c;群管理体系的设立&#xff0c;规则的制定&#…

阅读react-redux源码(七) - 实现一个react-redux

阅读react-redux源码 - 零阅读react-redux源码 - 一阅读react-redux源码(二) - createConnect、match函数的实现阅读react-redux源码(三) - mapStateToPropsFactories、mapDispatchToPropsFactories和mergePropsFactories阅读react-redux源码(四) - connectAdvanced、wrapWithC…

[读书笔记]TCP/IP详解V1读书笔记-4 5

IP地址与以太网地址之间的关系 R P发送一份称作A R P请求的以太网数据帧给以太网上的每个主机。这个过程称作广播&#xff0c;在32 bit的I P地址和采用不同网络技术的硬件地址之间提供动态映射 ----------------------------------------- arp以太网帧的类型字段为x 0 8 0 6&am…

未来是Apache Karaf上的微服务架构

这是Jamie Goodyear的客座博客文章&#xff08; 博客 &#xff0c; icbts &#xff09;。 他是Savoir Technologies的开源倡导者&#xff0c;Apache开发人员和计算机系统分析师&#xff1b; 他为全球大型组织设计&#xff0c;批判和支持了体系结构。 他拥有纽芬兰纪念大学的计…

springcloud微服务多节点高性能、高可用、高并发部署

1. 共有三个服务 discovery服务&#xff0c;domain服务&#xff0c;gateway服务。 discovery服务是用来注册其他服务的&#xff0c;作为服务治理用。 domain服务是主业务服务。 gateway服务是所有服务的一个入口&#xff0c;用来做一些服务的判断和过滤用。 2. 有三台机器分别为…

只能是数字、字母、-和_

在文本框的keypress事件调用下面函数。 如 <input disabled"disabled" type"text" iduserNameToEdit οnkeypress"TextValidate()" /> 如果在文本框中按下特殊字符键&#xff0c;则显示警告信息&#xff0c;或者输入框不接受非法输入。 …