How to use React Hooks Context with multiple values for Providers

时间:2019-01-09 22:22:15

标签: reactjs react-hooks

What is the best way to share some global values and functions in react?

Now i have one ContextProvider with all of them inside:

<AllContext.Provider
  value={{
    setProfile, // second function that changes profile object using useState to false or updated value
    profileReload, // function that triggers fetch profile object from server
    deviceTheme, // object
    setDeviceTheme, // second function that changes theme object using useState to false or updated value
    clickEvent, // click event
    usePopup, // second function of useState that trigers some popup
    popup, // Just pass this to usePopup component
    windowSize, // manyUpdates on resize (like 30 a sec, but maybe can debounce)
   windowScroll // manyUpdates on resize (like 30 a sec, but maybe can debounce)
  }}
>

But like sad in docs: Because context uses reference identity to determine when to re-render, there are some gotchas that could trigger unintentional renders in consumers when a provider’s parent re-renders. For example, the code below will re-render all consumers every time the Provider re-renders because a new object is always created for value:

This is bad:

<Provider value={{something: 'something'}}>

This is ok:

this.state = {
      value: {something: 'something'},
    };
<Provider value={this.state.value}>

I imagine that in future i will have maybe up to 30 context providers and it's not very friendly :/

So how can i pass this global values and functions to components? I can just

  1. Create separate contextProvider for everything.
  2. Group something that used together like profile and it's functions, theme and it's functions (what about reference identity than?)
  3. Maybe group only functions because thay dont change itself? what about reference identity than?)
  4. Other simpliest way?

Examples of what i use in Provider:

// Resize
  const [windowSize, windowSizeSet] = useState({
    innerWidth: window.innerWidth,
    innerHeight: window.innerHeight
  })
// profileReload
const profileReload = async () => {
    let profileData = await fetch('/profile')
    profileData = await profileData.json()

    if (profileData.error)
      return usePopup({ type: 'error', message: profileData.error })

    if (localStorage.getItem('deviceTheme')) {
      setDeviceTheme(JSON.parse(localStorage.getItem('deviceTheme'))) 
    } else if (profileData.theme) {
      setDeviceTheme(JSON.parse(JSON.stringify(profileData.theme)))
    } else {
      setDeviceTheme(settings.defaultTheme) 
    }
    setProfile(profileData)
  }

// Click event for menu close if clicked outside somewhere and other
const [clickEvent, setClickEvent] = useState(false)
const handleClick = event => {
  setClickEvent(event)
}
// Or in some component user can change theme just like that
setDeviceTheme({color: red})

5 个答案:

答案 0 :(得分:5)

(从性能的角度来看)关于将哪些内容组合在一起的主要考虑因素是,较少地将哪些内容一起使用,而更多地将哪些内容一起更改。对于大多数一次(或至少很少)进入上下文的事物,您可以将它们放在一起而没有任何问题。但是,如果其中某些事情混合在一起的变化更加频繁,则可能有必要将它们分开。

例如,我希望deviceTheme对于给定的用户来说是相当静态的,并且可能被大量组件使用。我猜想popup可能正在管理您当前是否打开了一个弹出窗口,因此它可能会随着与打开/关闭弹出窗口相关的每项操作而改变。如果popupdeviceTheme在同一上下文中捆绑在一起,则每次popup更改时,都会导致依赖于deviceTheme的所有组件也重新呈现。因此,我可能会有一个单独的PopupContextwindowSizewindowScroll可能会有类似的问题。使用哪种确切的方法可以深入了解领域,但是对于不经常更改的部分,您可以使用AppContext,然后对更频繁更改的内容使用更具体的上下文。

下面的CodeSandbox演示了useState和useContext之间的交互,其中上下文分为几种不同的方式以及一些按钮来更新上下文中保存的状态。

Edit zk58011yol

您可以转到this URL在完整的浏览器窗口中查看结果。我鼓励您首先了解结果的工作方式,然后查看代码并尝试使用它,如果您想了解其他情况。

答案 1 :(得分:2)

This answer已经很好地解释了如何将上下文结构化以提高效率。但是最终目标是使上下文使用者仅在需要时进行更新。是否要具有单个或多个上下文取决于具体情况。

在这一点上,这个问题对于大多数全局状态React实现都是常见的,例如Redux。常见的解决方案是仅在需要时使用import sagemaker import boto3 import os import pickle with open('xgboost-model', 'r') as inp: cls.model = pkl.load(inp) React.PureComponentReact.memo钩子使使用者组件更新:

shouldComponentUpdate

const SomeComponent = memo(({ theme }) => <div>{theme}</div>); ... <AllContext> {({ deviceTheme }) => <SomeComponent theme={deviceTheme}/> </AllContext> 将仅在SomeComponent更新时重新呈现,即使上下文或父组件已更新。这可能是理想的,也可能不是理想的。

答案 2 :(得分:1)

You can still combine them! If you are concerned about performance, you can create the object earlier. I don't know if the values you use change, if they do not it is quite easy:

state = {
  allContextValue: {
    setProfile,
    profileReload,
    deviceTheme,
    setDeviceTheme,
    clickEvent,
    usePopup,
    popup,
    windowSize
  }
}

render() {
  return <AllContext.Provider value={this.state.allContextValue}>...</AllContext>;
}

Whenever you then want to update any of the values you need to do I like this, though:

this.setState({
  allContextValue: {
    ...this.state.allContextValue,
    usePopup: true,
  },
});

This will be both performant, and relatively easy as well :) Splitting those up might speed up a little bit, but I would only do that as soon as you find it is actually slow, and only for parts of your context that would have a lot of consumers.

Still, if your value does not change a lot, there is really nothing to worry about.

答案 3 :(得分:0)

Ryan 的回答很棒,您应该在设计如何构建上下文提供程序层次结构时考虑这一点。

我提出了一个解决方案,您可以使用该解决方案来更新具有许多 useState 的提供程序中的多个值

示例:

const TestingContext = createContext()


const TestingComponent = () => {
    const {data, setData} = useContext(TestingContext)
    const {value1} = data
    return (
        <div>
            {value1} is here
            <button onClick={() => setData('value1', 'newline value')}>
                Change value 1
            </button>
        </div>
    )
}

const App = () => {
    const values = {
        value1: 'testing1',
        value2: 'testing1',
        value3: 'testing1',
        value4: 'testing1',
        value5: 'testing1',
    }

    const [data, setData] = useState(values)

    const changeValues = (property, value) => {
        setData({
            ...data,
            [property]: value
        })
    }

    return (
        <TestingContext.Provider value={{data, setData: changeValues}}>
            <TestingComponent/>
            {/* more components here which want to have access to these values and want to change them*/}
        </TestingContext.Provider>
    )
    }

答案 4 :(得分:0)

根据 Koushik 的回答,我制作了自己的 typecipt 版本。

    {'type': 'FeatureCollection', 'features': [{'type': 'Feature', 'geometry': '{"type":"Polygon","coordinates":[[[6.66079022243348,51.140794993202],[6.66079005460558,51.1407983122385],[6.66081135709435,51.1407987385067],[6.66080873391236,51.1407981018504],[6.66079022243348,51.140794993202]]]}', 'properties': {'AreaOfCoverage': '0.647782903636197', 'ETRa_soil': '0.0400227641046727', 'ETRc_soil': '7.65935710118916', 'PECgw': '4168.4374316502'}}, {'type': 'Feature', 'geometry': '{"type":"MultiPolygon","coordinates":[[[[6.66049410863497,51.1409985164652],[6.66049411228518,51.1409984442868],[6.66049407370026,51.1409984842113],[6.66049410863497,51.1409985164652]]],[[[6.66049457721976,51.14098925077],[6.66049543865696,51.1409722168828],[6.66044876649505,51.1409712828309],[6.66049457721976,51.14098925077]]]]}', 'properties': {'AreaOfCoverage': '0.177577611929162', 'ETRa_soil': '0.0934526392159067', 'ETRc_soil': '17.8845002791712', 'PECgw': '9733.24776807721'}}, {'type': 'Feature', 'geometry': '{"type":"MultiPolygon","coordinates":[[[[6.66064910499184,51.1407591404876],[6.66064726863041,51.1407954549773],[6.66068859193834,51.1407962819142],[6.66065225500977,51.1407598944706],[6.66064910499184,51.1407591404876]]],[[[6.66077024294677,51.1407979158214],[6.66079009430318,51.1407983130556],[6.66079026183779,51.1407949998192],[6.66078137299918,51.1407935071077],[6.66077024294677,51.1407979158214]]]]}', 'properties': {'AreaOfCoverage': '0.28852769378483', 'ETRa_soil': '0.0808452757479024', 'ETRc_soil': '15.4717658999718', 'PECgw': '8420.16989926723'}}, {'type': 'Feature', 'geometry': '{"type":"Polygon","coordinates":[[[6.66043337245854,51.1408810874443],[6.66049997989679,51.1408824204657],[6.6605039746486,51.1408034284145],[6.66049858662808,51.140809049721],[6.66049847250583,51.1408012466777],[6.66049259787335,51.1408071550042],[6.66047598480274,51.1408275084349],[6.66046929349543,51.1408382571074],[6.66046911886301,51.1408388831836],[6.66046910890004,51.1408398037521],[6.66045458061045,51.1408549610759],[6.66043750722066,51.1408759348598],[6.66043337245854,51.1408810874443]]]}', 'properties': {'AreaOfCoverage': '0.95875163585475', 'ETRa_soil': '0.00468709090198103', 'ETRc_soil': '0.896992094052197', 'PECgw': '488.168311170785'}}, {'type': 'Feature', 'geometry': '{"type":"Polygon","coordinates":[[[6.66078551152349,51.1408881565072],[6.66078106877664,51.1409760174891],[6.66079877671441,51.1409582633473],[6.66086141144714,51.1408929620131],[6.66086410806563,51.1408896813464],[6.66078555930881,51.1408881095832],[6.66078551152349,51.1408881565072]]]}', 'properties': {'AreaOfCoverage': '0.991780933222734', 'ETRa_soil': '0.000933940385583422', 'ETRc_soil': '0.178732855774211', 'PECgw': '97.2714441215027'}}, {'type': 'Feature', 'geometry': '{"type":"Polygon","coordinates":[[[6.66050693190458,51.1407926465578],[6.660647308328,51.1407954557945],[6.66064914425548,51.1407591498856],[6.66055958831034,51.1407377138789],[6.66055364416397,51.1407365156578],[6.66055029102368,51.1407377976343],[6.6605477857488,51.1407392764561],[6.6605423532381,51.1407449238168],[6.66052985094832,51.1407603229531],[6.66050511836349,51.1407913964812],[6.66050693190458,51.1407926465578]]]}', 'properties': {'AreaOfCoverage': '0.987662605743044', 'ETRa_soil': '0.00140190985931724', 'ETRc_soil': '0.268290521067109', 'PECgw': '146.011242953987'}}, {'type': 'Feature', 'geometry': '{"type":"Polygon","coordinates":[[[6.66044883557746,51.1409713099265],[6.66049543739402,51.1409722425705],[6.66049998115972,51.1408823947779],[6.66043339276621,51.1408810621376],[6.66042514768543,51.1408913368421],[6.66040117907167,51.1409214363123],[6.66038337074439,51.1409456331738],[6.66044883557746,51.1409713099265]]]}', 'properties': {'AreaOfCoverage': '0.884982556662815', 'ETRa_soil': '0.0130695416268265', 'ETRc_soil': '2.50118373151128', 'PECgw': '1361.21449256459'}}, {'type': 'Feature', 'geometry': '{"type":"Polygon","coordinates":[[[6.66079005586835,51.1407982865507],[6.66078739343633,51.1408509398627],[6.66079862849856,51.1408537515861],[6.66083550854172,51.14084867975],[6.66083544122551,51.1408552077224],[6.66083994787324,51.1408619381473],[6.66081827230877,51.1408582818435],[6.66080951847558,51.1408645822662],[6.66078553364671,51.1408881347828],[6.6608640872722,51.1408897066434],[6.66087268473994,51.1408792470862],[6.6608755937829,51.1408754379299],[6.66087625948697,51.1408743642673],[6.66087913518067,51.1408732603238],[6.66088228444444,51.1408703553614],[6.66089792427524,51.1408551089074],[6.66089838909667,51.1408543986984],[6.66086119388093,51.1408463694017],[6.66084373055219,51.1408475490385],[6.66084829866778,51.1408469208198],[6.66086689496409,51.1408297548763],[6.66087267925071,51.1408199773584],[6.66087271360274,51.1408164704356],[6.66085760189237,51.140809962283],[6.66081124163047,51.1407987104832],[6.66079005586835,51.1407982865507]]]}', 'properties': {'AreaOfCoverage': '0.71412562714461', 'ETRa_soil': '0.0324841772488655', 'ETRc_soil': '6.21665992475359', 'PECgw': '3383.28107539983'}}, {'type': 'Feature', 'geometry': '{"type":"MultiPolygon","coordinates":[[[[6.66063818546419,51.1409750735191],[6.66063601279755,51.1410180379841],[6.66065184757205,51.1410167513147],[6.66067158288883,51.1410138185135],[6.66068332505489,51.1410049696782],[6.66070780973692,51.1409816258827],[6.66071018823114,51.1409765143888],[6.66063818546419,51.1409750735191]]],[[[6.66077919587118,51.1409778952804],[6.66075474410624,51.140977405988],[6.66075649787208,51.1409800818877],[6.66076946524305,51.1409837590433],[6.6607757339826,51.1409813661995],[6.66077919587118,51.1409778952804]]]]}', 'properties': {'AreaOfCoverage': '0.253302540397098', 'ETRa_soil': '0.0848479434751155', 'ETRc_soil': '16.2377764983391', 'PECgw': '8837.05439872202'}}, {'type': 'Feature', 'geometry': '{"type":"Polygon","coordinates":[[[6.66049539895922,51.1409722160655],[6.66049453825359,51.1409892354866],[6.66049790592691,51.1409905563584],[6.66050254127054,51.140989925155],[6.66049799619706,51.1409944255302],[6.66049407370026,51.1409984842113],[6.66051538223784,51.141018157541],[6.66052910659558,51.1410238285246],[6.66054704819211,51.1410252668449],[6.66063605270061,51.1410180347417],[6.66063822516193,51.1409750743363],[6.66049539895922,51.1409722160655]]]}', 'properties': {'AreaOfCoverage': '0.691031936305826', 'ETRa_soil': '0.0351083353328678', 'ETRc_soil': '6.71885821877395', 'PECgw': '3656.59150331816'}}, {'type': 'Feature', 'geometry': '{"type":"MultiPolygon","coordinates":[[[[6.66064272769041,51.1408852514052],[6.66063818420133,51.1409750992069],[6.66071017637666,51.1409765398646],[6.66071390500723,51.1409685268629],[6.66071055126937,51.1409439099285],[6.66072623612857,51.140919757016],[6.66071856834969,51.1409093255937],[6.66073228793538,51.1409103446131],[6.6607385396446,51.1408969789063],[6.66073714773113,51.1408962315432],[6.66073371339569,51.1408975378437],[6.66073857855034,51.1408933821359],[6.66073861291278,51.1408898752133],[6.6607385400128,51.140887168723],[6.66064272769041,51.1408852514052]],[[6.6607140598979,51.1409031921924],[6.66071925407906,51.140903108498],[6.66071518625459,51.1409047245139],[6.6607140598979,51.1409031921924]]],[[[6.66075476118234,51.1409774320427],[6.66077917072688,51.1409779204903],[6.66078111063798,51.1409759755185],[6.66078555333878,51.1408881154456],[6.66075054580207,51.1409224919393],[6.66074440965898,51.1409363995916],[6.66074370659916,51.1409389937458],[6.6607444014066,51.1409506996834],[6.66074604147812,51.140963503801],[6.66075052501954,51.1409709684949],[6.66075476118234,51.1409774320427]]]]}', 'properties': {'AreaOfCoverage': '0.762576290120202', 'ETRa_soil': '0.0269786822714604', 'ETRc_soil': '5.16304573807562', 'PECgw': '2809.87461892527'}}, {'type': 'Feature', 'geometry': '{"type":"MultiPolygon","coordinates":[[[[6.66064726989326,51.1407954292895],[6.66064272642756,51.1408852770929],[6.66073854070576,51.1408871944499],[6.66073851353583,51.140886185737],[6.6607323166692,51.1408730206179],[6.66072633929129,51.1408639970718],[6.66072044311788,51.1408590223929],[6.66069250955009,51.1408382566758],[6.66070162877013,51.1408352618304],[6.66070755137455,51.1408255770271],[6.6607075948258,51.1408218904088],[6.66070763373369,51.1408182936384],[6.660701651824,51.140809359939],[6.66068856573734,51.1407962556768],[6.66064726989326,51.1407954292895]]],[[[6.66078553362401,51.140888134805],[6.66078555237702,51.1408881351803],[6.6607855533768,51.1408881154083],[6.66078553362401,51.140888134805]]],[[[6.6607874326787,51.1408509496837],[6.66079009556595,51.1407982873678],[6.66077030473932,51.1407978913448],[6.66076970161208,51.1407981302489],[6.6607632693411,51.140803757614],[6.66075661643472,51.1408165756616],[6.6607557063733,51.1408260909554],[6.6607631205245,51.1408406295129],[6.66076956074425,51.1408461547086],[6.66078691024833,51.1408508189385],[6.6607874326787,51.1408509496837]]]]}', 'properties': {'AreaOfCoverage': '0.578273065296824', 'ETRa_soil': '0.0479212332350216', 'ETRc_soil': '9.17092675349607', 'PECgw': '4991.076125209'}}, {'type': 'Feature', 'geometry': '{"type":"Polygon","coordinates":[[[6.66050393269623,51.1408034721833],[6.66049994019913,51.1408824196485],[6.66064276612522,51.1408852779101],[6.66064730959085,51.1407954301067],[6.66050689348607,51.1407926200758],[6.66052970983289,51.1408083474096],[6.66053340789023,51.1408106991555],[6.66053071998254,51.1408106734032],[6.66051715086203,51.1408022500543],[6.66050733224076,51.1408013340471],[6.66050499250535,51.1408023664872],[6.66050393269623,51.1408034721833]],[[6.66054102438944,51.1408274780477],[6.66055347300262,51.1408331963643],[6.66055543626421,51.1408337241709],[6.66054747174923,51.1408359543041],[6.66054741919786,51.1408398206177],[6.66054875587623,51.1408478722288],[6.66054102438944,51.1408274780477]],[[6.66055928654052,51.1408326460601],[6.66055931325502,51.1408307949571],[6.66055935895622,51.1408271998522],[6.66056613056901,51.1408288627964],[6.66057106131433,51.1408293490214],[6.66055928654052,51.1408326460601]]]}', 'properties': {'AreaOfCoverage': '0.983466593572459', 'ETRa_soil': '0.00187870671846284', 'ETRc_soil': '0.359537527380078', 'PECgw': '195.670428655349'}}, {'type': 'Feature', 'geometry': '{"type":"Polygon","coordinates":[[[6.66049994146206,51.1408823939607],[6.66049539769628,51.1409722417533],[6.66063822389907,51.1409751000241],[6.66064276738808,51.1408852522223],[6.66049994146206,51.1408823939607]],[[6.6605684300883,51.1409345855812],[6.66057302348829,51.1409272138277],[6.66057303103794,51.1409265161076],[6.66057526186566,51.1409300185161],[6.66057298002594,51.1409309004456],[6.6605684300883,51.1409345855812]]]}', 'properties': {'AreaOfCoverage': '0.99896577029807', 'ETRa_soil': '0.000117520506010963', 'ETRc_soil': '0.0224904886603103', 'PECgw': '12.2399561150095'}}]}