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.
Related
I have a huge component with 15 subcomponents, each of them have 1/2 queries, and some of them have 1 or 2 mutations.
Some queries are shared between components, but some of them are specific to that component.
Right now I have all mutations + queries in a separate file, as functions that return the query/mutation, and all the fetching functions.
Should I only keep the shared queries in this file? And move the specific queries/mutations to a file inside each component file?
Personally, I will keep the actions, etc in files closest to the component it is used in, or shared across. The reason is that if and when you decide to move or delete those components, it is extremely easy to garbage collect the redundant code, as well as general maintenance of code beforehand - you just delete the folder and know that it's dependencies are never used anywhere else other than deeper within the component.
Example:
- /BlogPost/
- /components/
- /BlogPostSocialMedia/
- /index.jsx
- /index.jsx
Assuming the above structure - lets say I have a component called BlogPost, which contained a sub-component BlogSocialMedia.
If the BlogSocialMedia had an action that is used only within that component, I would place it in a file within the /BlogSocialMedia directory. Maybe /BlogPost/components/BlogSocialMedia/actions.js?
However, if there was a query or action that was used by both the BlogPost and the BlogPostSocial component, I would place it one directory back, in /BlogPost/actions.js
Hopefully, you can see how this keeps your components nice and "packaged", and makes it much easier to maintain, move, and delete it in the future. The alternative is that you find yourself with a single file as you mention, which is extremely difficult to identify what code is stale and what isn't, and almost impossible to move around if you need to.
On a final note: Read into and understand the principle of [Single Responsibility][1]. It is far from optimal to have a single file which is responsible for so many different actions.
[1]: https://www.freecodecamp.org/news/solid-principles-single-responsibility-principle-explained/#:~:text=The%20Single%20Responsibility%20Principle%20(SRP,only%20one%20reason%20to%20change%22.
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
Let's imagine, in a OO world, I want to build a Torrent object which listens to the network and lets me interact with it. It would inherit an EventEmitter and would look something like this:
var torrent = new Torrent(opts)
torrent.on('ready', cb) // add torrent to the UI
torrent.on('metadata', cb) // update data in the UI
and I can also make it do things:
torrent.stop()
torrent.resume()
Then of course if I want to do delete the torrent from memory I can call torrent.destroy().
The cool thing about this OO approach is that I can easily package this functionality in its own npm module, test the hell out of, and give users a nice clean reusable API.
My question is, how do I achieve this with Cycle.js apps?
If I create a driver it's unclear how I would go about creating many torrents and having their own independent listeners. Also consider I'd like to package functionality in a way that others get to easily reuse it in other Cycle.js apps.
It seems to me that you are trying to solve a problem thinking about it as you would write "imperative code".
I think creating Torrent instances with their own listeners is not something you should be using in cycle components.
I would go about it differently - creating Torrent module and figuring out what would be its sources and sinks. If this module should be reusable and published, you can create it as a function that would receive streams as arguments. Maybe something similar to TodoMVC Task component (which is then used in its parent component).
Since this module can be created as a pure function, testing it should be at least just as easy.
This implementation of course depends on your requirements but communication with the module would then be done only with streams and since it would be declarative there would be no need for methods like stop() and destroyed() which you would call from elsewhere.
How do I test it?
In cycle.js you'd write a component with intent model and view functions.
You'd test intent(), for given input Streams, produces Streams of actions that you want. For models, you'd test that given http and action streams, you get the state you want, and for view, you test that given a state you get the VDom you want.
One tricky bit with cycle.js is that since it passes functions around, normal JavaScript objects that use the 'this' keyword are not worth the trouble due to 'this' context problems. If you are working with cycle.js and you think you might write a JS class for use with Isolate, Onionify, or Collections most likely, you are going in the wrong direction. See MDN docs about 'this'
how I would go about creating many torrents
The Cycle.js people have several ways to deal with groups of things like this.
This ticket describes some things that might work for that:
Wrap subapp in Web Component
Stanga and similars.
Cycle Collections
Cycle Onionify
So trying to get my hands dirty with KnockoutJS 3.2. I've read the docs and I've successfully implemented components within my current project. I don't use an AMD, so I'm just using script elements to hold the views.
My question is: If i'm not using the asynchronous loading features, is there any real practical difference to using components rather than templates?
General description of both
As stated in the other answer, a template is only a piece of HTML which can be bound to a viewmodel, or viewmodel section. And a component is composed of a template, and its corresponding viewmodel. Besides, this viewmodel, apart from observables can include some simple business logic, and functionality to communicate with the server.
Coupling and encapsulation
Another important difference is the coupling. A template it's bound to the main viewmodel, and its bound to the main viewmodel's observables, so it's highly coupled to the viewmodel: a change in the viewmodel will break the template, and viceversa. So, if you're reusing a template in several places, and you change it, you have to correct the corresponding viewmodels.
A component is bound to its own viewmodel. It's only coupled to the main viewmodel if there are parameters provided from it. This means that you can easily change the component template as well as the component viewmodel, and, if there are no parameters, or you don't change them, nothing will be broken.
So using components helps in decoupling and modularizing.
Communication between main viewmodel and component
The last section is a double edged sword: if there is a high interaction between the main viewmodel and the template or component, it's much easier to use a template, because all the logic and properties are held in the main viewmodel and the interactions are easily implemented. If you used a component you'd need to provide complex parameters, or even make something to allow the component to expose functionality to the main viewmodel.
Polymorphism
It's not strange to have some parts of an application that require different behaviors and visualization to solve the same kind of task. For example, let's imagine you have to implement a payment system in your application: if you accept for example paypal and credit card payment you have two different visualization and functionalities. If you used templates, you'd need to have the particular implementation of each payment system in the main viewmodel. If you used components, they'd share a common interface (parameters) but each of them would have its own implementation. If tomorrow you had to include a new payment system, it would be easy to implement a new component with the common interface.
NOTE: pay attention to the last paragraph
Binding
In the case of a template the binding it's not done at the template level, but inside it. I.e. each element inside the template must be bound to observables of the main viewmodel. In the case of a component the binding is much simpler: at most, it requires the component name and the parameters, if they exist.
Component registration and custom tags
If you register the component you can use custom tags. This makes the views more easyly readable and understandable: instead of specifying the component name in a binding, you use a tag with the component name, and parameters are passed as attributes.
Dynamic loading
If you use templates you have to dynamically load them by yourself, and, as this is an asynchronous task, you'll have to take care of using the template only when it's already available. That's way in most occasions you'll use inline templates. This is not good if they must be reused in several places.
If you have used some AMD implementation, like require.js, and you understand the benefits of this technology, you'll be happy to know that you can easily use AMD to load component templates and viewmodels. One of the advantages is that you don't have to worry about the template or component being available when you need to use them.
Testability
No matter if you do manual or automated tests, it's much easier to test a bunch of independent components, one by one, that to test a complex viewmodel with or without templates.
My choice
So far, I've exposed facts about templates, and components, and I've tried not to show my personal preferences. However, in this last section, I must say that in most situations I prefer to use components for their advantages:
modularity
low coupling
easy reuse
testability
binding syntax
(optional) dynamic loading
However, templates are also a better fit on some occasions
The last paragraph have to do with big applications. If you're dealing with small applications or simply enhancements of interfaces rendered by another technology (like ASP.NET MVC), you'll probably get none of the advantages of using components. So, you don't need them.
There are other cases when it's not worth using components. For example, if you have to show a list (JavaScript array) of items which have different properties which must be shown in a different way, it's easier to use templates. Note that the choice in this case is because each of the instances doesn't have a complex viewmodel with a lot of functionality, but a simple bunch of properties. In this particular case it's not only not worth, but it can also be counterproductive to use components.
You can understand this last example as polymorphism. But, in this case it's nearly "visual" polymorphism. I.e. each kind of item must be shown in a different way, but there is no need to implement any special logic in each of the components.
However, even in this case, if the templates are complex enough, or must be used in many different places, it's also much better to use a simple component that includes the template as well as a parameter that receives the whole item. So, even in this case, it's not a bad idea to use components.
If you'd read this far, thank you, and I hope you have some criteria to help you choosing the best option.
They aren't completely different. Components are made up of templates (html) and data/logic (view model i.e. JavaScript). When you have a modular view you want to attach a view model to you can utilize components. Here's a link discussing components a bit more: http://www.knockmeout.net/2014/06/knockout-3-2-preview-components.html