• 主页
  • 标签
  • 归档
  • 搜索
  • Github

March 29, 2021

React Context vs global values

本文为转载文章, 仅用于自己的知识管理收集, 如果涉及侵权,请联系 suziwen1@gmail.com,会第一时间删除
收集该文章,并非代表本人支持文中观点,只是觉得文章内容容易引起思考,讨论,有它自有的价值

转载自: https://www.codelime.blog/react-context-vs-global-values/

One topic I can say I commonly hear when discussing with fellow devs is the justification of using React’s Context for “holding” a value when you can:

  • export it from a module
  • attached a global value on the window object
  • define it as and environment variable and let your bundler get it from process.env.

These are all simple and clean (as in obvious) ways to keep global and constant values. By “global” I mean entire-application-global. Same for the “constant” notion, although, you could trigger an explicit re-rendering on the app when a setter function is called.

Bellow I will give an example of these two conditions slightly diverging and that’s when Context shows it’s usefulness. We are omitting props drilling, of course, assuming you’d like to avoid that, since you arrived at deciding between Context or globals.

Take the case of a range of colors for some elements. Let’s say a pallet of colors for a website featuring interior design.

Values exported from a module

For comparison I will tackle only this case of defining global value. Let us create a file where you’ll write the following.

  1. 1// colors.js 

  2. 2export const colors = ["#4B6F80", "#E3F6FF", "#96DEFF", "#08608A", "#78B2CC"]; 

Then import it in a component:

  1. 1// ColoredBlocks.js 

  2. 2import React from "react"; 

  3. 3import { colors } from "./colors"; 

  4. 4 

  5. 5export default function ColoredBlocks() { 

  6. 6 return colors.map(c => <div style={{ background: c }} />); 

  7. 7} 

Finally, display your pallet.

  1. 1// App.js 

  2. 2import ColoredBlocks from "./ColoredBlocks"; 

  3. 3// other imports ... 

  4. 4 

  5. 5function App() { 

  6. 6 return ( 

  7. 7 <div className="App"> 

  8. 8 <ColoredBlocks /> 

  9. 9 </div> 

  10. 10 ); 

  11. 11} 

  12. 12// render root ... 

And the visual output would be:


Everything works and looks nice. This is fine when the component tied to the colors is itself a singular element in the app.

Yet, once you need to render, the ColoredBlocks component cannot be reused with other values (remember, prop passing is assumed not to be an option).

Values provided by Context

Many apps have context providers as a single, close to root wrapper around all the app. Be it React Router, Redux, Appolo Graphql, it’s likely you’ll see just one of the providers and lots of consumers arbitrarily spread throughout the code.

However, when actively reading the Context documentation you’ll see the first subtitle “Context provides a way to pass data through the component tree“. A few paragraphs down the page it writes “it will read the current context value from the closest matching Provider above it in the tree“.

We know from a the datastructures 101 course that any subtree is a tree itself. React components are no different. That means we could have providers for several branches.

Let’s redefine the ColoredBlocks component. I’ve defined the context in the same file, but you could easily have it elsewhere.

  1. 1// ColoredBlocks.js 

  2. 2import React from "react"; 

  3. 3 

  4. 4export const ColorsContext = React.createContext(["black"]); 

  5. 5 

  6. 6export function ColoredBlocks() { 

  7. 7 return ( 

  8. 8 <ColorsContext.Consumer> 

  9. 9 {colors => colors.map(c => <div style={{ background: c }} />)} 

  10. 10 </ColorsContext.Consumer> 

  11. 11 ); 

  12. 12} 

An leveraging it would like:

  1. 1// App.js 

  2. 2import { ColoredBlocks, ColorsContext } from "./ColoredBlocks"; 

  3. 3// other imports ... 

  4. 4 

  5. 5const coldColors = ["#4B6F80", "#E3F6FF", "#96DEFF", "#08608A", "#78B2CC"]; 

  6. 6const warmColors = ["#801D13", "#FAD6CF", "#E0553D", "#804039", "#CC301F"]; 

  7. 7 

  8. 8function App() { 

  9. 9 return ( 

  10. 10 <div className="App"> 

  11. 11 <ColorsContext.Provider value={coldColors}> 

  12. 12 {/* ColoredBlocks can be nested however deep */} 

  13. 13 <ColoredBlocks /> 

  14. 14 </ColorsContext.Provider> 

  15. 15 <br /> 

  16. 16 <ColorsContext.Provider value={warmColors}> 

  17. 17 <ColoredBlocks /> 

  18. 18 </ColorsContext.Provider> 

  19. 19 </div> 

  20. 20 ); 

  21. 21} 

  22. 22// render root ... 

This produces the desired visual output:


It’s true, one would probably define the color values in a different module or config file, but it’ll only be passed to the ColorsProvider and it won’t “litter” your application code.

Conclusion

That’s one of the advantages the Context API offers over global values. It’s the ability to work with the component tree. Any tree, therefore code (components) can be shared and reused, inside the same app and cross projects. It bring flexibility whilst sticking to a standard. This is part of React’s philosophy, to work with your hierarchy as much as possible. Actually, the mindset is a good practice for software development in general, and is loosely known as the Dependency Injection principle.

Tagged with 文章 | 转载 | 技术 | react
Time Flies, No Time for Nuts
Copyright © 2020 suziwen
Build with  Gatsbyjs  and  Sculpting theme