当前位置: 首页 > news >正文

图标网站导航制作怎么做/网站外贸推广

图标网站导航制作怎么做,网站外贸推广,做校招的网站有哪些,php网站开发软件转眼间2017年已经过了一半了,看到之前有人问是否完成了自己半年的计划,答案是:当然没有啦。感觉自己现在对技术产生了敬畏,因为要学习的知识是在是太多了,而自己的时间和精力却很难达到目标,目前处在比较焦虑的状态。自…

  转眼间2017年已经过了一半了,看到之前有人问是否完成了自己半年的计划,答案是:当然没有啦。感觉自己现在对技术产生了敬畏,因为要学习的知识是在是太多了,而自己的时间和精力却很难达到目标,目前处在比较焦虑的状态。自己是年初进入掘金的,半年内虽然文章的阅读量不错但是关注度太低,半年就混了40个关注,说来真是惭愧。
  
  扯远了,我们言归正传,上次的文章Redux:百行代码千行文档解释了Redux内部的运作原理。但是我们在React中很少会直接搭配使用Redux,而是通过React-Redux绑定React与Redux。这篇文章我们我们将了解React-Redux其中的奥秘。在阅读之前希望你有React-Redux的使用经验,否则这篇文章可能不太适合你。
  
  首先我们可以看看React-Redux的源码目录结构,大致看一下,做到心里有数。

.
├── components
│ ├── Provider.js
│ └── connectAdvanced.js
├── connect
│ ├── connect.js
│ ├── mapDispatchToProps.js
│ ├── mapStateToProps.js
│ ├── mergeProps.js
│ ├── selectorFactory.js
│ ├── verifySubselectors.js
│ └── wrapMapToProps.js
├── index.js
└── utils
├── PropTypes.js
├── Subscription.js
├── shallowEqual.js
├── verifyPlainObject.js
├── warning.js
└── wrapActionCreators.js

  首先来看一下index.js:


import Provider, { createProvider } from './components/Provider'
import connectAdvanced from './components/connectAdvanced'
import connect from './connect/connect'export { Provider, createProvider, connectAdvanced, connect }复制代码

  我们可以看出来,React-Redux对外提供的API有四个:ProvidercreateProvider,connectAdvanced,connect。我们将从connectAdvanced开始介绍。

connectAdvanced

  其实我在看React-Redux源码之前都不知道有这个API,为了方便后面的源码理解,我们介绍一下connectAdvanced:
  
connectAdvanced(selectorFactory, [connectOptions])

  connectAdvanced用来连接组件到Redux的store上。是connect函数的基础,但并没有规定如何将statepropsdispatch处理传入最终的props中。connectAdvanced并没有对产生的props做缓存来优化性能,都留给了调用者去实现。connectAdvanced并没有修改传入的组件类,而是返回一个新的、连接到store的组件类。

参数:

  • selectorFactory(dispatch, factoryOptions): selector(state, ownProps): props (Function),用来初始化selector函数(在每次实例的构造函数中)。selector函数在每次connector component需要计算新的props(在组件传递新的props和store中数据发生改变时会计算新的props)都会被调用。selector函数会返回纯对象(plain object),这个对象会作为props传递给被包裹的组件(WrappedComponent)
  • [connectOptions] (Object) 如果定义了该参数,用来进一步定制connector:
      1. [getDisplayName] (Function): 用来计算connector component的displayName。
      2. [methodName] (String) 用来在错误信息中显示,默认值为connectAdvanced
      3. [renderCountProp] (String): 如果定义了这个属性,以该属性命名的值会被以props传递给包裹组件。该值是组件渲染的次数,可以追踪不必要的渲染。
      4. [shouldHandleStateChanges] (Boolean): 控制conntector组件是否应该订阅redux store中的state变化。
      5. [storeKey] (String): 你想要从context和props获得store的key值,只有在需要多个store的情况下才会用到(当然,这并不是明智的选择)。默认是store
      6. [withRef] (Boolean): 如果是true,存储被包裹组件的实例,并可以通过函数getWrappedInstance获得该实例,默认值为false
      7. 在connectOptions中额外的属性会被传递给selectorFactory函数的factoryOptions属性。

返回:

  函数返回一个高阶组件,该高阶组件将从store的state中构建的props传递给被包裹组件。

例如:

// 按照用户信息选择性传入todos的部分信息
import * as actionCreators from './actionCreators'
import { bindActionCreators } from 'redux'function selectorFactory(dispatch) {let ownProps = {}let result = {}const actions = bindActionCreators(actionCreators, dispatch)const addTodo = (text) => actions.addTodo(ownProps.userId, text)return (nextState, nextOwnProps) => {const todos = nextState.todos[nextProps.userId]const nextResult = { ...nextOwnProps, todos, addTodo }ownProps = nextOwnPropsif (!shallowEqual(result, nextResult)) result = nextResultreturn result}
}
export default connectAdvanced(selectorFactory)(TodoApp)复制代码

 讲了这么多,我们看看connectAdvanced是如何实现的,一开始本来想把所有的代码都列出来,但是感觉直接列出200多行的代码看着确实不方便,所以我们还是一部分一部分介绍:

//代码整体结构
function connectAdvanced(selectorFactory,{getDisplayName = name => `ConnectAdvanced(${name})`,methodName = 'connectAdvanced',renderCountProp = undefined,shouldHandleStateChanges = true,storeKey = 'store',withRef = false,...connectOptions} = {}
) {return function wrapWithConnect(WrappedComponent) {class Connect extends Component {//......  return hoistStatics(Connect, WrappedComponent)}
}复制代码

  函数接受两个参数:selectorFactoryconnectOptions(可选),返回一个高阶组件wrapWithConnect(以属性代理方式实现),高阶组件中创建了组件类Connect, 最后返回了hoistStatics(Connect, WrappedComponent)。其中hoistStatics来源于:

import hoistStatics from 'hoist-non-react-statics'复制代码

作用是将WrappedComponent中的非React特定的静态属性(例如propTypes就是React的特定静态属性)赋值到Connect。作用有点类似于Object.assign,但是仅复制非React特定的静态属性。

  其实对于React-Redux之所以可以使得Provider中的任何子组件访问到Redux中的store并订阅store,无非是利用context,使得所有子组件都能访问store。更进一步,我们看看高阶组件时如何实现:   

let hotReloadingVersion = 0
const dummyState = {}
function noop() {}function connectAdvanced(selectorFactory,{getDisplayName = name => `ConnectAdvanced(${name})`,methodName = 'connectAdvanced',renderCountProp = undefined,shouldHandleStateChanges = true,storeKey = 'store',withRef = false,...connectOptions} = {}
) {const subscriptionKey = storeKey + 'Subscription'const version = hotReloadingVersion++const contextTypes = {[storeKey]: storeShape,[subscriptionKey]: subscriptionShape,}const childContextTypes = {[subscriptionKey]: subscriptionShape,}return function wrapWithConnect(WrappedComponent) {const wrappedComponentName = WrappedComponent.displayName|| WrappedComponent.name|| 'Component'const displayName = getDisplayName(wrappedComponentName)const selectorFactoryOptions = {...connectOptions,getDisplayName,methodName,renderCountProp,shouldHandleStateChanges,storeKey,withRef,displayName,wrappedComponentName,WrappedComponent}class Connect extends Component {}return hoistStatics(Connect, WrappedComponent)}
}复制代码

  上面的代码并没有什么难以理解的,connectAdvanced中定义了subscriptionKeyversion以及为Connect组件定义的contextTypeschildContextTypes(不了解context的同学可以看这里)。在高阶组件中所作的就是定义组装了selectorFactory所用到的参数selectorFactoryOptions。接下来介绍最重要的组件类Connect:   

    class Connect extends Component {constructor(props, context) {super(props, context)this.version = versionthis.state = {}this.renderCount = 0this.store = props[storeKey] || context[storeKey]this.propsMode = Boolean(props[storeKey])this.setWrappedInstance = this.setWrappedInstance.bind(this)this.initSelector()this.initSubscription()}getChildContext() {const subscription = this.propsMode ? null : this.subscriptionreturn { [subscriptionKey]: subscription || this.context[subscriptionKey] }}componentDidMount() {if (!shouldHandleStateChanges) returnthis.subscription.trySubscribe()this.selector.run(this.props)if (this.selector.shouldComponentUpdate) this.forceUpdate()}componentWillReceiveProps(nextProps) {this.selector.run(nextProps)}shouldComponentUpdate() {return this.selector.shouldComponentUpdate}componentWillUnmount() {if (this.subscription) this.subscription.tryUnsubscribe()this.subscription = nullthis.notifyNestedSubs = noopthis.store = nullthis.selector.run = noopthis.selector.shouldComponentUpdate = false}getWrappedInstance() {return this.wrappedInstance}setWrappedInstance(ref) {this.wrappedInstance = ref}initSelector() {const sourceSelector = selectorFactory(this.store.dispatch, selectorFactoryOptions)this.selector = makeSelectorStateful(sourceSelector, this.store)this.selector.run(this.props)}initSubscription() {if (!shouldHandleStateChanges) returnconst parentSub = (this.propsMode ? this.props : this.context)[subscriptionKey]this.subscription = new Subscription(this.store, parentSub, this.onStateChange.bind(this))this.notifyNestedSubs = this.subscription.notifyNestedSubs.bind(this.subscription)}onStateChange() {this.selector.run(this.props)if (!this.selector.shouldComponentUpdate) {this.notifyNestedSubs()} else {this.componentDidUpdate = this.notifyNestedSubsOnComponentDidUpdatethis.setState(dummyState)}}notifyNestedSubsOnComponentDidUpdate() {this.componentDidUpdate = undefinedthis.notifyNestedSubs()}isSubscribed() {return Boolean(this.subscription) && this.subscription.isSubscribed()}addExtraProps(props) {if (!withRef && !renderCountProp && !(this.propsMode && this.subscription)) return propsconst withExtras = { ...props }if (withRef) withExtras.ref = this.setWrappedInstanceif (renderCountProp) withExtras[renderCountProp] = this.renderCount++if (this.propsMode && this.subscription) withExtras[subscriptionKey] = this.subscriptionreturn withExtras}render() {const selector = this.selectorselector.shouldComponentUpdate = falseif (selector.error) {throw selector.error} else {return createElement(WrappedComponent, this.addExtraProps(selector.props))}}}Connect.WrappedComponent = WrappedComponentConnect.displayName = displayNameConnect.childContextTypes = childContextTypesConnect.contextTypes = contextTypesConnect.propTypes = contextTypesif (process.env.NODE_ENV !== 'production') {Connect.prototype.componentWillUpdate = function componentWillUpdate() {// We are hot reloading!if (this.version !== version) {this.version = versionthis.initSelector()if (this.subscription) this.subscription.tryUnsubscribe()this.initSubscription()if (shouldHandleStateChanges) this.subscription.trySubscribe()}}}复制代码

  我们首先来看构造函数:

constructor(props, context) {super(props, context)this.version = versionthis.state = {}this.renderCount = 0this.store = props[storeKey] || context[storeKey]this.propsMode = Boolean(props[storeKey])this.setWrappedInstance = this.setWrappedInstance.bind(this)this.initSelector()this.initSubscription()
}复制代码

  首先我们先看看用来初始化selectorinitSelector函数:

//Connect类方法
initSelector() {const sourceSelector = selectorFactory(this.store.dispatch, selectorFactoryOptions)this.selector = makeSelectorStateful(sourceSelector, this.store)this.selector.run(this.props)
}
//connectAdvanced外定义的函数
function makeSelectorStateful(sourceSelector, store) {// wrap the selector in an object that tracks its results between runs.const selector = {run: function runComponentSelector(props) {try {const nextProps = sourceSelector(store.getState(), props)if (nextProps !== selector.props || selector.error) {selector.shouldComponentUpdate = trueselector.props = nextPropsselector.error = null}} catch (error) {selector.shouldComponentUpdate = trueselector.error = error}}}return selector
}复制代码

  我们知道,selector的主要作用是用来从store中的stateownProps中计算新的props,并返回纯对象(plain object),这个对象会作为props传递给被包裹的组件(WrappedComponent)。在initSelector中,首先调用selectorFactory从而初始化sourceSelector,我们并不会直接调用sourceSelector,而是为了程序的健壮,通过将sourceSelector作为参数调用makeSelectorStateful,返回更加安全的selector。从此之后,我们想要生成新的props只需要调用selector.run函数。在selector.run函数中对sourceSelector的异常做了处理,并用sourceSelector.error记录是否存在异常。sourceSelector.shouldComponentUpdate用来根据前后两次返回的props是否相同,从而记录是否应该刷新组件,这就为后期的性能提升留出了空间,只要在前后数据相同时,我们就返回同一个对象,使得shouldComponentUpdatefalse,就可以避免不必要的刷新,当然这不是我们selector的职责,而是sourceSelector所需要做的。每次返回的新的props都会记录在selector.props以备后用。

  再看initSubscription函数之前,我们需要先了解一下Subscription类:   

// 为连接到redux的store的组件以及嵌套的后代组件封装订阅逻辑,以确保祖先组件在后代组件之前刷新
const CLEARED = null
const nullListeners = { notify() {} }function createListenerCollection() {
//代码逻辑来源与store中let current = []let next = []return {clear() {next = CLEAREDcurrent = CLEARED},notify() {const listeners = current = nextfor (let i = 0; i < listeners.length; i++) {listeners[i]()}},subscribe(listener) {let isSubscribed = trueif (next === current) next = current.slice()next.push(listener)return function unsubscribe() {if (!isSubscribed || current === CLEARED) returnisSubscribed = falseif (next === current) next = current.slice()next.splice(next.indexOf(listener), 1)}}}
}export default class Subscription {constructor(store, parentSub, onStateChange) {this.store = storethis.parentSub = parentSubthis.onStateChange = onStateChangethis.unsubscribe = nullthis.listeners = nullListeners}addNestedSub(listener) {this.trySubscribe()return this.listeners.subscribe(listener)}notifyNestedSubs() {this.listeners.notify()}isSubscribed() {return Boolean(this.unsubscribe)}trySubscribe() {if (!this.unsubscribe) {this.unsubscribe = this.parentSub? this.parentSub.addNestedSub(this.onStateChange): this.store.subscribe(this.onStateChange)this.listeners = createListenerCollection()}}tryUnsubscribe() {if (this.unsubscribe) {this.unsubscribe()this.unsubscribe = nullthis.listeners.clear()this.listeners = nullListeners}}
}复制代码

  首先我们先看函数createListenerCollection,这边的代码逻辑和redux中的listener逻辑一致,可以了解一下之前的文章Redux:百行代码千行文档。createListenerCollection通过闭包的方式存储currentnext,然后返回

{clear,notify,subscribe
}复制代码

作为对外接口,分别用来清除当前存储的listener、通知、订阅,其目的就是实现一个监听者模式。然后类Subscription封装了订阅的逻辑,Subscription根据构造函数中是否传入了父级的订阅类Subscription实例parentSub,订阅方法trySubscribe会有不同的行为。首先看看parentSub的来源:

//this.propsMode来自于constructor中的this.propsMode = Boolean(props[storeKey]),storeKey默认为`store`
const parentSub = (this.propsMode ? this.props : this.context)[subscriptionKey]复制代码

  我们知道Provider的主要作用就是通过context向子组件提供store,而在conectAdvanced函数的参数connectOptions中的storeKey是用来区分从context和props获得store的key值,只有在需要多个store的情况下才会用到,当然这并不是什么好事,毕竟Redux追求的是单个store。例如你设置了storeKeyotherStore,那么就可以通过给wrapWithConnect返回的组件添加属性otherStore,从而注入新的store
  下面我们区分几种情况:

情况1:

  如果Provider中的子组件连接到Redux的store,并且祖先组件都没有连接到Redux的store,也就是说是当前组件是通往根节点的路径中第一个连接到Redux的store的组件,这时候直接可以使用Redux的store中的subscribe方法去订阅store的改变。对应于的代码是tryUnsubscribe方法中的   

this.store.subscribe(this.onStateChange)。复制代码

情况2:

  如果当前组件并不是通往根节点的路径中第一个连接到Redux的store的组件,也就是父组件中存在已经连接到Redux的store的组件。这时候,必须要保证下层的组件响应store改变的函数调用必须晚于父级组件响应store的函数调用,例如在图中红色的组件在store更新时是晚于黑色的组件的。代码中是如下实现的,在父级组件中,如下:

getChildContext() {const subscription = this.propsMode ? null : this.subscriptionreturn { [subscriptionKey]: subscription || this.context[subscriptionKey] }
}复制代码

因此在子组件(红色)中就可以通过context获得父组件的subscription(也就是parentSub)。这样在执行
tryUnsubscribe时对应于

this.parentSub.addNestedSub(this.onStateChange)复制代码

这样我们将子组件处理store中state的函数添加到parentSub中的listener中。这样在父组件更新结束后,就可以调用this.notifyNestedSubs()。这样就保证了更新顺序,子组件永远在父组件更新之后。

情况3:

  如上图所示,右边的组件是通过属性prop的方式传入了store,那么组件中的this.store中的值就是通过以props传入的store。假如祖先元素没有连接到store的组件,那么当前组件中parentSub值就为空。所以订阅的方式就是以props中的store:   

this.store.subscribe(this.onStateChange)。复制代码

情况4:

  如上图所示,右下方的组件的父组件(紫色)是通过props传入store的,那么在父组件(紫色)中有   

getChildContext() {const subscription = this.propsMode ? null : this.subscriptionreturn { [subscriptionKey]: subscription || this.context[subscriptionKey] }
}复制代码

父组件对子组件暴露context,其中context中的subscriptionKey属性值为this.context[subscriptionKey],要么是null,要么是祖先元素中props方式传入store的组件subscription。也就是说以props传入的store的父组件不会影响子组件的订阅store。感觉说的太过于抽象,我们举个例子:

在上面这个例子中,如果发出dispatch更新store1,组件A和组件C都会刷新,组件B不会刷新。
  
  讨论了这么多,我们可以看一下initSubscription的实现方式:   

initSubscription() {if (!shouldHandleStateChanges) returnconst parentSub = (this.propsMode ? this.props : this.context)[subscriptionKey]this.subscription = new Subscription(this.store, parentSub, this.onStateChange.bind(this))this.notifyNestedSubs = this.subscription.notifyNestedSubs.bind(this.subscription)
}复制代码

  如果当前的store不是以props的方式传入的,那么parentSubthis.context[subscriptionKey]。如果是以props的方式传入的,若显式地给组件以props的方式传入subscription时,parentSub值为this.props.subscription。需要注意的是,我们在initSubscription中拷贝了当前this.subscription中的notifyNestedSubs方法,目的是防止在notify循环过程中组件卸载,使得this.subscriptionnull。我们在组件卸载时,会将值赋值为一个名为no-loop的空函数,避免出错。当然这并不是唯一的解决方法。
  接下我们可以看一下Connect组件中主要生命周期函数:

componentDidMount() {if (!shouldHandleStateChanges) returnthis.subscription.trySubscribe()this.selector.run(this.props)if (this.selector.shouldComponentUpdate) this.forceUpdate()
}componentWillReceiveProps(nextProps) {this.selector.run(nextProps)
}shouldComponentUpdate() {return this.selector.shouldComponentUpdate
}componentWillUnmount() {if (this.subscription) this.subscription.tryUnsubscribe()this.subscription = nullthis.notifyNestedSubs = noopthis.store = nullthis.selector.run = noopthis.selector.shouldComponentUpdate = false
}复制代码

  组件在did mount时会根据可选参数shouldHandleStateChanges选择是否订阅storestate改变。组件在接受props时,会使用selector计算新的props并执行相应的声明周期。shouldComponentUpdate会根据this.selector存储的值shouldComponentUpdate来判断是否需要刷新组件。在组件will mount时会做相应的清理,防止内存泄露。

  接着我们介绍其他的类方法:

getWrappedInstance() {return this.wrappedInstance
}setWrappedInstance(ref) {this.wrappedInstance = ref
}复制代码

  getWrappedInstancesetWrappedInstance在可选参数withRef为true时,获取或者存储被包裹组件的实例(ref)

onStateChange() {this.selector.run(this.props)if (!this.selector.shouldComponentUpdate) {this.notifyNestedSubs()} else {this.componentDidUpdate = this.notifyNestedSubsOnComponentDidUpdatethis.setState(dummyState)//dummyState === {}}
}notifyNestedSubsOnComponentDidUpdate() {this.componentDidUpdate = undefinedthis.notifyNestedSubs()
}复制代码

  onStateChange函数是store发生改变的回调函数,当回调onStateChange方法时,会通过selector计算新的props,如果计算selcetor的结果中shouldComponentUpdatefalse,表示不需要刷新当前组件仅需要通知子组件更新。如果shouldComponentUpdatetrue,会通过设置this.setState({})来刷新组件,并使得在组件更新结束之后,通知子组件更新。

addExtraProps(props) {if (!withRef && !renderCountProp && !(this.propsMode && this.subscription)) return propsconst withExtras = { ...props }if (withRef) withExtras.ref = this.setWrappedInstanceif (renderCountProp) withExtras[renderCountProp] = this.renderCount++if (this.propsMode && this.subscription) withExtras[subscriptionKey] = this.subscriptionreturn withExtras
}复制代码

  addExtraProps函数主要用作为selector计算出的props增加新的属性。例如,ref属性用来绑定回调存储组件实例的函数setWrappedInstancerenderCountProp为当前组件属性刷新的次数,subscriptionKey用来传递当前connect中的subscription

render() {const selector = this.selectorselector.shouldComponentUpdate = falseif (selector.error) {throw selector.error} else {return createElement(WrappedComponent, this.addExtraProps(selector.props))}
}复制代码

  render函数其实就是高阶函数中的属性代理,首先将shouldComponentUpdate置回false,然后根据selector中的计算过程是否存在error,如果存在error就抛出,否则执行   

createElement(WrappedComponent, this.addExtraProps(selector.props))复制代码

如果你对上面语句不太熟悉,其实上面代码等同于:

return (<WrappedComponent{...this.addExtraProps(selector.props)}/>
)复制代码

  其实所谓的jsx也无非是createElement语法糖,所有的jsx的语法都会被编译成React.createElement,所以哪怕你的代码中没有显式的用到React,只要有jsx语法,就必须存在React。   

if (process.env.NODE_ENV !== 'production') {Connect.prototype.componentWillUpdate = function componentWillUpdate() {// We are hot reloading!if (this.version !== version) {this.version = versionthis.initSelector()if (this.subscription) this.subscription.tryUnsubscribe()this.initSubscription()if (shouldHandleStateChanges) this.subscription.trySubscribe()}}
}复制代码

  React-Redux在生产环境下是不支持热重载的,只有在开发环境下提供这个功能。在开发环境中,组件在will update时会根据this.versionversion去判断,如果两者不一样,则初始化selector,取消之前的订阅并重新订阅新的subscription

Provider


import { Component, Children } from 'react'
import PropTypes from 'prop-types'
import { storeShape, subscriptionShape } from '../utils/PropTypes'
import warning from '../utils/warning'let didWarnAboutReceivingStore = false
function warnAboutReceivingStore() {if (didWarnAboutReceivingStore) {return}didWarnAboutReceivingStore = truewarning('<Provider> does not support changing `store` on the fly. ' +'It is most likely that you see this error because you updated to ' +'Redux 2.x and React Redux 2.x which no longer hot reload reducers ' +'automatically. See https://github.com/reactjs/react-redux/releases/' +'tag/v2.0.0 for the migration instructions.')
}export function createProvider(storeKey = 'store', subKey) {const subscriptionKey = subKey || `${storeKey}Subscription`class Provider extends Component {getChildContext() {return { [storeKey]: this[storeKey], [subscriptionKey]: null }}constructor(props, context) {super(props, context)this[storeKey] = props.store;}render() {return Children.only(this.props.children)}}if (process.env.NODE_ENV !== 'production') {Provider.prototype.componentWillReceiveProps = function (nextProps) {if (this[storeKey] !== nextProps.store) {warnAboutReceivingStore()}}}Provider.propTypes = {store: storeShape.isRequired,children: PropTypes.element.isRequired,}Provider.childContextTypes = {[storeKey]: storeShape.isRequired,[subscriptionKey]: subscriptionShape,}Provider.displayName = 'Provider'return Provider
}export default createProvider()复制代码

  首先我们看看函数createProvider,createProvider函数的主要作用就是定制Provider,我们知道Provider的主要作用是使得其所有子组件可以通过context访问到Redux的store。我们看到createProvider返回了类Provider,而类ProvidergetChildContext函数返回了{ [storeKey]: this[storeKey], [subscriptionKey]: null },使得所有子组件都能访问到store。需要注意的是,要想使得子组件访问到context必须同时定义两点:getChildContext函数与static childContextTypes = {}。并且我们知道Redux 2.x 与React-Redux 2.x不再支持热重载的reducer,所以在非生产环境下,我们会为Provider添加生命周期函数componentWillReceiveProps,如果store的值发生了变化,就会在提供警告提示。
  Providerrender函数中返回了Children.only(this.props.children)ChildrenReact提供的处理组件中this.props.children的工具包(utilities)返回仅有的一个子元素,否则(没有子元素或超过一个子元素)报错且不渲染任何东西。所以Provider仅支持单个子组件。
  
  最后欢迎大家关注我的掘金账号或者博客,不足之处,欢迎指正。

http://www.lbrq.cn/news/1292779.html

相关文章:

  • 网站地图怎么做、/杭州网站建设 seo
  • 网站安全建设模板下载/广州网站建设工作室
  • 大数据营销工具/系统优化软件十大排名
  • 专业做网站建设公/站长seo推广
  • 红杉网站建设/aso优化排名违法吗
  • 工厂怎么做网站/搜狗搜索引擎推广
  • 聊城做wap网站服务/中国进入一级战备状态了吗
  • 石岩网站建设 0755/济南网络推广
  • 微信小程序案例展示/关键词优化快速排名
  • wordpress 替换jquery/seo是什么意思 seo是什么职位
  • wordpress 伪静态 windows/搜索引擎营销seo
  • 网站开发维护的好处/站长工具是干嘛的
  • 上线了做网站怎么样/朋友圈广告推广文字
  • 京东优惠券网站怎么做/什么是互联网销售
  • 动态网页设计网站建设/sem是什么方法
  • 龙泉市做网站企业/排名优化哪家好
  • 乌鲁木齐城乡建设委员会的网站/外贸网站制作公司
  • 一个新网站要怎么做seo/百度手机助手苹果版
  • 白银市城乡建设局网站/详情页设计
  • 网站制作公司报价/5118站长工具箱
  • 大理石在哪些网站做宣传/淘宝代运营靠谱吗
  • 动态网站开发平台/网络广告策划案
  • 兰州网站建设/百度投广告怎么收费
  • 游戏网站设计风格有哪些/seo博客网站
  • 广州 网站建设 行价/seo数据是什么
  • jtbc网站开发教程/优帮云首页推荐
  • 织梦体育网站模板/百度网址安全中心
  • wordpress导入表单/广州网站优化步骤
  • 中国三农建设工作委员会官方网站/站长之家点击进入
  • 网站注册页面怎么做数据验证/2021年近期舆情热点话题
  • 计算机网络第四章(3)——网络层《IPV4(子网划分、子网掩码)》
  • 将 RustFS 用作 GitLab 对象存储后端
  • 复制docker根目录遇到的权限问题
  • Docker 在 Ubuntu 系统中的详细操作指南
  • NX二次开发常用函数坐标转化UF_MTX4_csys_to_csys和UF_MTX4_vec3_multipl
  • Keil编译文件格式转换全解析