I have inherited some code that uses props drilling to pass down a large list of constants (translations) to various sub components. These translations map a symbol to a local language text and there is also a function to do the mapping called translate. ie {translate(SYM_NO)} would return "NON" if the local language was French.
I thought Props drilling was a bit messy and decided to use the new Context in React 16.3.1. This worked OK for JSX, but was a bit tricky when I needed to get translate into JS eg a MS Fabric UI DetailsList callback so that the callback could translate various column data (returned by an API call). Below is a technique for adding a parameter (from Context) to the callback which can then be used in the callback implementation:
onRenderItemColumn={(item, index, column) => this._renderItemColumn(item, index, column, translate)}
After getting this to work, I discovered that it was actually unececessary, as I could just import translation in any (most) of my components and easily use translate anywhere in my JSX or JS :-
import translate from "../../../config/translate";
So I am now wondering about the performance/memory implications of importing translate in nearly all of my components. Is there a penalty for every import or is it just the first import that counts and the rest have no impact?
Should I continue with many imports or revert to (trickier) Context or perhaps some other method. (Props drilling is not an option I think)
Peter (React newb)
Assuming your using a standard Webpack based React stack the overhead with regards to performance should be minimal since they all are references the same module which is only evaluated once. Maintenance wise, in my experience, it will soon become a burden. Especially when you take into account that imports are relative to the file you import in. "is this file four levels deep or six". Making moving files a pain. And adding aliases for some modules so you can import them with an absolute path increases the complexity for new developers.
Context would not be the best approach I think since you need to add consumers to all parts that need translations.
What I would advise you to look into is if higher order components click for you. That has the benefits of not cluttering your components render logic with consumers and can be added as extra functionality to all components who need translations in a pretty transparent way. In pseudo code: export default withTranslations(Component);
You would still need to import the withTranslation where you would import your config/translations module but implementation wise it would make more sense to me.
Also there are some NPM modules for i18n in React and all the ones I've used also use the higher order component approach, which makes me believe that it can also work for you.
Related
I am working on a React project which is divided into several modules and each module contains several components. There is also a commons module which contains components which are common to two or more separate modules. I am using context API for managing all the state. Below is the structure of the parent component(App.js). Module1Container, Module2Container... contains components of respective modules.
return(
<CommonsContextProvider>
<Module1ContextProvider>
<Module1Container />
</Module1ContextProvider>
<Module2ContextProvider>
<Module2Container />
</Module2ContextProvider>
<Module3ContextProvider>
<Module3Container />
</Module3ContextProvider>
</CommonsContextProvider>
)
I mainly want the states to be seperate as a single context for every module will make it too much cluttered. Is it a good idea to have a separate context for each module and a common context for commonly used state across modules? Don't this structure voids the single source of truth rule? Better suggestion is most welcome.
This method currently have no problem, but on the long run, if you need to maintain the project single source of truth is still better,
For single source of truth use redux (redux-hooks) and
incase you need to have modular kinda of view of states use different reducers for different component and common reducer for global state,then combine them using combineReducer of redux
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
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
I'm new to React (and React Native in particular), and I'm trying to come up with the right application design.
I have a separate JavaScript module, unrelated to React; the module contains some objects with methods, some of them mutate objects, some have side effects (like, subscribe/unsubscribe to/from the server events, or add/remove listeners to local object's events), etc.
I'd like to reuse this JavaScript module inside my React Native app, but it seems that it won't play well together. In Redux (and some other state managers as well), state needs to be represented as a plain immutable JS object, and instead of mutating existing objects, we create new objects instead. So I can't use my existing JS objects as a state directly.
I probably could use some wrappers around my existing JS code (mutating, and full of side effects), but it doesn't seem a nice solution: a lot of repetition, and the end result is unlikely to be elegant.
On the other hand, I'm not quite happy reimplementing the whole thing to fit into React's world, to make it idiomatic.
And on the one more other hand, I could just forget about Redux, and use plain state of React's components, but I feel it'll be a mess.
I'd like to get some suggestions from experiensed React + Redux people. What would you recommend?
It's hard to say exactly without seeing what the mystery module does or exposes. But consider converting the module into one or more reducers and then use Redux's combineReducers to target pieces of the overall store that will be contained exclusively in your module.
Then you will need to add reducer methods that always return new objects as required by Redux, but you won't need to modify every function in the existing code.
This article by Dan Abramov helped me understand reducer composition.
See also Handling Actions in the docs for help on how to write good reducer methods that only modify a small piece of the store.
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