Sharing data across React components - javascript

In front-end apps there is often data which needs to be accessed by many components. Routing is one example, another is configuration data, e.g. feature switches, default language, etc.
In an app that isn't using any particular framework, I might share this configuration data across modules using
export class Configuration {
static getConfig () {
// get the config from the server
return axios.get('/config').then(function (response) {
return response;
})
}
}
Then import this class into any module that needs to access configuration data. With some front-end framework, it's obvious how to share such "global" data, e.g.
AngularJS - Configuration should be defined as a service that's dependency-injected into any controllers/directives/services that need to access config. data
Vue.js - use a mixin
However, when using ReactJS it's not obvious which approach should be used. Possible options are:
A plain-old JavaScript module. Encapsulate the data to be shared as a function/method, and import it into any React components that need to access it. The seems like the simplest approach, but I have the feeling that when writing a ReactJS app everything should be defined as a component, rather than JavaScript classes/functions.
Redux seems to be recommended approach for sharing-state within large apps, but this feels like overkill for smaller projects
Something else?

but I have the feeling that when writing a ReactJS app everything
should be defined as a component, rather than JavaScript
classes/functions.
I really don't see a reason why everything should be a component in React. If it is just data, you can create a single instance of that JS object say and import that anywhere you need it.
I have used similar thing in my app, where I had a "global" kind of object which was saving different configs etc, and then I was using that in the components which needed that data.
Here is also some more info about component communication in React.

A plain-old JavaScript module. Encapsulate the data to be shared as a function/method, and import it into any React components that need
to access it. The seems like the simplest approach, but I have the
feeling that when writing a ReactJS app everything should be defined
as a component, rather than JavaScript classes/functions.
I disagree, React is a library that helps to create user interfaces through components but it doesn't mean that (services, translations, configuration data) have to be built into components, on the other hand, it's actually discouraged you shouldn't couple your services/configuration to a library
you should limit the scope of React to what it is used for. So using plain-old JavaScript modules feels the right way to implement a simple react app.
Redux seems to be recommended approach for sharing-state within large
apps, but this feels like overkill for smaller projects
I think it depends on the complexity of the app rather the size, here is where you should think on, how does your app will evolve or if redux isn't what you really need to remove all this data-sharing dependency within React.
Something else?
The react context (discourage)
The observable pattern
https://www.npmjs.com/package/react-observable-subscribe

I think you should go for the redux solution. It sounds like an over kill but it has an added advantage of having a global state object, therefore you can easily choose when to re-render your app when data is shared across compoents.

you can use context in react :
https://reactjs.org/docs/context.html
or you can create a global variable in window object too
the other way is to use observer design pattern plagin and use it.
mobX or other stateManagement component is good too beside redux

Related

Access instance/service from Vuex that was provided to Vue (Vue.js 3)

Background
Consider the following:
// app.js
import API from 'utils/API';
const api = new API(config.app.urls.api, endpoints, token);
app.provide('$api', api);
Based on everything I have read in the past 24 hours, the above is the advised method of providing a 'service' to Vue.js 3.
However, the issue with the above is that I now cannot access the API instance as the inject method cannot be used outside of a Vue component.
As such, when I want to import the API instance into my Vuex modules, I can't...
Question
Is there an 'advised' way of accessing a provided service outside of a Vue component? Or is one of my proposed solutions below how it should be done?
Possible Solutions
Proposed Solution 1
Instead of providing the service to Vue, we can just add it to the global properties like so:
// app.js
app.config.globalProperties.$api = api;
and then we can access it like so in the store:
// some-vuex-module.js
import { getCurrentInstance } from 'vue';
const api = getCurrentInstance().appContext.config.globalProperties.$api;
I am using the above for certain things in my app but for the API service it just seems wrong to do it this way.
Proposed Solution 2
Another solution I thought of was to just make the API instance available to the window like so:
// app.js
import API from 'utils/API';
const api = window.api = new API(config.app.urls.api, endpoints, token);
app.provide('$api', api);
The above seems like an anti-pattern though...
The preferable method in modular environment (which Vue 3 setup is commonly is) is to just import api in places where it's used, regardless of whether it's used inside or outside the component.
The solution with Vue global property originated at the time when Vue applications weren't necessarily modular so they relied on Vue instance as global application scope. Currently it's suitable only for properties that are primarily used in a template and require boilerplate code to import and expose them. The example is $t in vue-i18n.
The solution with provide/inject is usable for cases that need dependency injection. A common case is a library that require dependencies to be loosely coupled. Another one is that a dependency depends on component hierarchy and may vary between components.
The solution with window should be avoided, unless application is divided into separate scripts that cannot interact through common JS modules. Even then the problem is that a script that defines global variable should be loaded before those that use it.

I wonder if I can have a redux store in the library and the App also have a redux store

I'm really new to React and need to ask.
Can I have a ReactJs Redux store in a library and then use that library in an App that also has a Redux store?
Both of them do this:
<Provider store={store}>
..App
</Provider>
I learn ReactJs and am not sure I understand how this is built up how Webpack is loading the code here.
Will these two React Stores collide?
Can they exist independently?
Can they share Reducers? (let's say the App want to use the library Redux store and send a dispatch to it )
I have tested doing some of this but can't make it work. It's like Redux after first loading the library Redux store then it can't load the App store but I'm a novice so must ask
Will these two React Stores collide? / Can they exist independently?
Two different stores created with createStore will not collide, and can exist independently.
behind the scenes, each store instance has a subscribe method, and its own subscribers array.
When using the react-redux Provider component, you are sending an instance of the store down the component tree with React's context API. The instance will be available to all children and decedents of the component which rendered the Provider. If there is another Provider in the way, that Provider's value will override the higher up Provider.
Thus, if you use another Provider with another instance of a store in your library, it will take effect only for the component tree starting from your library component. With the correct composition, there will be no collision.
Can they share Reducers?
Reducers are nothing but pure functions, meaning they shouldn't have any side effects. So you could export and reuse the same reducer logic if you want, you'll just need to register them with every store instance.
Lastly, I disagree with other answers here which claim you shouldn't use multiple stores. You have the exact use case where a separate store would be justified, where you have your main application using one store, and you have a standalone library that uses another unrelated global state.
In my opinion, everything is possible in the programming world, definitely, having a multi-store is possible too.
You asked several questions, first of all, I answer them and then explain a little bit more.
Can I have a Reactjs Redux store in a library and then use that library in an App that also has a Redux store?
Yeah, it's possible, the famous library that makes Redux easy to use is Redux Toolkit, which has a very easy flow to use and implement in your application, even it has a CRA template that you can create your application (zero-config) based on redux npx create-react-app [my-app-name] --template redux or redux-typescript npx create-react-app my-app --template redux-typescript. it works properly.
Will these two React Stores collide?
Can they exist independently?
No, they won't collide because each store (never mind it is redux, mobx, or whatever) has a Provider and you should wrap part of your application or entire of it by using that <Provider store={store}>, so if you wanna have two stores, you can add two Providers and they won't collide. but, in connecting, and getting some data from stores, you should pay attention that which Provider you are going to call from. so they will be able to exist independently.
<ReduxOneProvider store={storeOne}>
<ReduxTwoProvider store={storeTwo}>
<MobxProvider store={mobXStore}>
<App>
</MobxProvider>
</ReduxTWoProvider>
</ReduxOneProvider>
But, totally, I'm not a fan of having multi-store, for more info read here
Can they share Reducers? (let's say the App want to use the library Redux store and send a dispatch to it )
Yes, you know, reducer functions are separate pure functions, located in a folder, when you wanna build your stores, you should gather these functions and combine them, so, the answer is yes, but please consider, the connect function which comes from react-redux want two functions, mapStateToProps and mapDispatchToProps, inside the second you can call a reducer by using dispatch function. so you will have re-render in all stores.
my opinion:
Please avoid having a multi-store, even having one and dealing with it, makes the project a little bit hard to maintain. how you wanna deal with multi. it makes complicated issues.
Yes it is possible.
To keep it simple, library is completely independent package where you can use the redux in normal way. And as you export the library's components to outer world, in same way export the store or dispatch which you would like to use in your application which is consuming the library.

React architectural problem - Best way of having a single global application state, updating child components when changed

I'm quite new to React, and I'm making a single page application with React.
So far, I've build the application with components and child components, having their own local state, however the child components doesn't really interact with one another, which is what I want them to, basically, with the least amount of boiler plate code...
The problem I'm facing, is that a change in some child component, should be able to update the state of another child component, somewhere else in the component tree.
A selection in one child component should also be able to trigger a function in another component updating it with data and so on.
I've considered having just one global application state, that all components can call and update when something in them changes, and this one application state will then update other components in the tree. Kinda like having a single "controller" with it's own state, that all components "views" can call, and which updates the states of other components as needed. (I'm used to WPF and MVC style of GUI programming).
What I've considered:
One could try to implement this with callback functions defined in the top of the hierarchy, to be sent down through the hierarchy and called from a child component when it changes.
This method however results in a LOT of boilerplate code that just passes functions to their child components. It feels wrong and hard to maintain...
To avoid all this passing around and boilerplate code, I've tried using a React Context, however this is not working as well as I hoped. I can only access the context from within the render function and from lifecycle functions, and sadly I often get complicated errors that are hard to understand. It seems like I'm exploiting React Context to do something you shouldn't use it for...
I've considered using a singleton pattern in JavaScript, however then that singleton needs to have a reference to the root component, and query for the component it needs to change... This seems like kind of a hack, and may not be that pretty, but idk.
I'm considering trying out React Redux however it seems to work in many ways similar to React Context (I'll be honest, I haven't read much into it yet).
What I need:
I need to ask someone with greater React experience than me: How do you keep a global application state, and update child components based on changes to the global application state? Also: Am I thinking about this all wrong? Am I trying to do something in a non-react way, failing to see how I should do it in React?
You can happily go with Redux or MobX, they're fine.
I suggest Taming The State from Robin Wieruch: https://roadtoreact.com/course-details?courseId=TAMING_THE_STATE
There are the book and the course. He shows different ways of handling React state.
Redux was created specifically for the problem yo stated.
Reacts follows a top-down down-top unidirectional flow in essence. Context API is useful in simple use cases but would fail horribly in a large scale application where you'd be creating consumers everywhere.
I'd suggest investing some time in Redux so that will save your precious time in long run.
There's a reason all big three frameworks require a state management library to be useful for large scale complex apps. (Angular has NgRx and Vue has Vuex).

What's The React Way To Handle Shared Helper Functions?

I'm somewhat new to React, and I'm trying to figure out where the best place is to put various functions that need to be used across my app.
For example, I have a function some code that returns a document_type key based on the document extension that is passed to it.
I also have a romanize function that takes a number and turns it into a roman numeral.
I also have a set of functions that are grouped around making API calls and parsing the response.
All of these need to be accessed in various places across the app. It's my understanding that the "React Way" is composability through component creation, but it's hard for me to see how these would make sense as components since components have to return JSX I believe.
You could create e.g. a utils file, export your helpers from there, and import them when needed:
// utils.js
export function romanize(str) {
// ...
}
export function getDocumentType(doc) {
// ...
}
// App.js
import { romanize } from './utils';
There are some situations where you will need a helper functions like these and setting those up in a util or helpers folder is a great way to handle that.
However, to take full advantage of React, I'd suggest thinking about if there is a way you could make a shared component instead. For functions such as your romanize function, you can make a React component that formats the number you pass it and displays it in a span. This is the same approach react libraries use, for example the react-intl library recommends using their <FormattedMessage /> component instead of their formatMessage helper function.
For example,
const RomanNumeral = ({ number }) => {
// romanize logic here
return <span>{result}</span>
}
Then you can use it like so:
<RomanNumeral number={5} />
The "react way" is to structure these files in the way that makes most sense for your application. Let me give you some examples of what react applications tend to look like to help you out.
React has a declarative tree structure for the view, and other related concepts have a tendency to fall into this declarative tree structure form as-well.
Let's look at two examples, one where the paradigm relates to the view hierarchy and one where it does not.
For one where it does not, we can think about your domain model. You may need to structure local state in stores that resemble your business model. You business model will usually look different from your view hierarchy, so we would have a separate hierarchy for this.
But what about the places where the business model needs to connect to the view layer. Since we are specifying data on a per component bases. Even though it isn't the view or styles or how the component behaves, this is still colocated in the same folder hierarchy as the react component because it fits into the same conceptual structure.
Now, there is your question of utilities. There are many approaches to this.
If they are all small and specific to your application but not any part, you can put them in the root under utils.
If there are a lot of utils and they fit into a structure separate from any of your existing hierarchies, make a new hierarchy.
If they are independent from your application, either of the above approaches could become an npm package.
If they relate to certain parts of your app, you can put them at the highest point in the hierarchy such that everything that uses the utility is beneath the directory where the utility lives.
Shared Conmponents is definetly the react way but having reusable functions in the utility/helper folder is always handy.
Here is how I would do it.
You could create a utility folder inside src folder where you could export all the reusable functions
--| src
----| utility
-------| formatDate.js
-------| formatCurrency.js
-------| romanize.js
----| components
----| hooks
----| api
Then you could import the functions inside your components

React with Redux? What about the 'context' issue?

I normally post code related stuff on Stack, but this is more a question about what the general thoughts of the community are.
There seems to be a lot of people advocating the use Redux with React to manage data/state, but while reading and learning both I've come across something that doesn't quite look right.
Redux
At the bottom of this page: http://redux.js.org/docs/basics/UsageWithReact.html (Passing the Store) it recommends using the "Magic" of React 'Context'.
One option would be to pass it as a prop to every container component. However it gets tedious, as you have to wire store even through presentational components just because they happen to render a container deep in the component tree.
The option we recommend is to use a special React Redux component called to magically make the store available to all container components...
React
On the React Context page (https://facebook.github.io/react/docs/context.html) it has a warning at the top:
Context is an advanced and experimental feature. The API is likely to change in future releases.
Then at the bottom:
Just as global variables are best avoided when writing clear code, you should avoid using context in most cases...
Do not use context to pass your model data through components. Threading your data through the tree explicitly is much easier to understand...
So...
Redux recommends using the React 'Context' feature rather than passing the store along down to each component via 'props'. While React recommends the opposite.
Also, it seems that Dan Abramov (the creator of Redux) now works for Facebook (the creator of React), just to confuse me more.
Am I reading all this right..?
What is the general current consensus on this issue..?
Context is an advanced feature and is subject to change. In some cases its conveniences outweigh its downsides so some libraries like React Redux and React Router choose to rely on it despite the experimental nature.
The important part here is the word libraries. If context changes its behavior, we as library authors will need to adjust. However, as long as the library doesn’t ask you to directly use the context API, you as the user shouldn’t have to worry about changes to it.
React Redux uses context internally but it doesn’t expose this fact in the public API. So you should feel much safer using context via React Redux than directly because if it changes, the burden of updating the code will be on React Redux and not you.
Ultimately React Redux still supports always passing store as a prop so if you want to completely avoid context, you have that choice. However I would say this is impractical.
TLDR: Avoid using context directly unless you really know what you are doing. Using a library that happens to rely on context internally is relatively safe.
I don't know about others, but I prefer using react-redux's connect decorator to wrap my components so that only the props from the store I need are passed into my component. This justifies the use of context in a sense because I am not consuming it (and I know, as a rule, any code that I am in charge of will not consume it).
When I test my components, I test the non-wrapped component. Because react-redux only passed the props I needed on that component, I now know exactly what props I need when I'm writing the tests.
I suppose the point is, I don't ever see the word context in my code, I don't consume it, so to a certain degree, it doesn't affect me! This doesn't say anything about Facebook's "experimental" warning.. If context disappeared, I'd be just as screwed as everyone else until Redux was updated.
There's an npm module that makes it really easy to add redux to the react context
https://github.com/jamrizzi/redux-context-provider
https://www.npmjs.com/package/redux-context-provider
import React, { Component } from 'react';
import ReduxContextProvider from 'redux-context-provider';
import createStore from './createStore';
import actions from './actions';
import Routes from './routes';
export default class App extends Component {
render() {
return (
<ReduxContextProvider store={store} actions={actions}>
<Routes />
</ReduxContextProvider>
);
}
}
React ships with all the features you need to handle your state without a single additional library. Most of your application's states should not be global as they live just fine in a useState or useReducer or custom hook next to your components.
So before you dive into the world of advanced state management (e.g. Redux), consider using the tools React ships with out of the box.
If you are interested in learning a bit more about this, I'd recommend this article by Andy Fernandez, which dives into the details on Redux: Context API vs Redux

Categories

Resources