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
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 have a little question about Angular Components.
I often read that you should use components only to display data and interact with the user, and for your "business logic" you should prefer services.
So my question is the following (just an example):
Let's say I have made a component to upload files via drag and drop. I have the logic to get the data from the drag and drop and store it in an array (and maybe much more other functions) inside that components typescript file.
Now when I am including this component twice inside one parent component (because I need two upload fields for example), are both referencing to the same or is also the program logic inside that component created twice for each instance?
If so, then I should try to keep as much shared program logic as possible in singleton services so they are only created once at runtime and not wasting memory etc., shouldn't I?
Hope somebody understands what I am meaning :).
thanks in advance!
If you add the component twice into your parent, then two different instances will be created (each owning unique scope).
You should however abstract upload/handling logic into a service. Provide that service in module to make it a singleton. If you want instance per component, then provide it inside component.
If you create two components in your template which are similar for example:
<app cumstom></app custom>
<app cumstom></app custom>
This will result in two objects being created who both have their own model (data) and view. They don't know anything of each other.
If you want them to communicate it is often smart to use a service which you can inject into both components so they can share the same data. If a service is provided in your ngmodule is will only be created once (so it is a singleton).
Well I think what you need is a smart component, where you can put your boths uploads-component and inject your service logic in this smart component. The smart component will be responsible to provide the bridge of the common logic between the two components.
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.
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've noticed that react projects tend to be organized like this,
/src
/actions
userActions.js
settingsActions.js
/components
userComponent.js
settingsComponent.js
/containers
userContainer.js
settingsContainer.js
/reducers
userReducers.js
settingsReducers.js
coupled on type rather than functionality like,
/src
/user
userActions.js
userComponent.js
userContainer.js
userReducers.js
/settings
settingsActions.js
settingsComponent.js
settingsContainer.js
settingsReducers.js
Why is that? To my understanding React is good in part because it couples css, html and js together instead of having them separate. Why not do it with the file structure as well?
There is no one true way to organize your files and directories, it varies with the opinions. But people still wonder what the best method for organising the code is.
I usually prefer the structure where containers, components, actionCreators, services and reducers are segregated. Whichever pattern you are following, you can make it more and more granular once your codebase scale up. I hope you are familiar with the idea of Presentational vs. Container components.
In the first pattern, components/ just hold the dumb stateless components that just takes props. This pattern very well support the concept of reusability. When you develop a large application, it happens quite often that you need to create a component that you definitively know you won’t reuse anywhere else, but you need it.
The containers/ have the stateful components which make API calls. Same way, if you are using redux in your application, many people tries to follow the ducks pattern where you define all the reducers in a single directory along with your root reducer, just to make things more granular and easy to access, and you don't have to jump between files to create an action.
This is just my perspective, but as I mentioned earlier, it totally depends on the use case of an application and also the opinion of the one who develops it. An alternative is to organize files by functional area as you mentioned in your second directory structure, with folders like users and settings kind of functionalities. This organization style starts off deceptively simple. But inevitably you end up with a folder common where you store very basic and common components like button, which are used all over your app, eventually you will end up with common/components and common/containers, but at one level deeper.
In short, start simple with whichever structure you want, you will eventually make it finer and finer with your use case and scale.