Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
I'm familiar with developing client-side applications in AngularJS, but now I'd like to start using ReactJS.
I also have an eye on the ReactNative which I think will revolutionize mobile apps .
What is the way of thinking and how the structure of a React application differs from Angular? What is the biggest difference?
Directives
If you're familiar with Angular, then the way to think about how React works is by imagining using Angular using only directives. React doesn't have any concept of controllers, services, factories or dependency injection. If focuses only on components (directives in Angular terms).
This is also the way that Angular is headed with Angular 2. Angular 2 introduces a concept called components, and removes the notion of directives, controllers and services/factories. Angular 2 still uses DI, but you're not tying your classes to the Angular world (which you do in Angular 1).
Scopes
So Angular uses scopes for data binding, and any template tied to a scope (or a parent scope) can read and print out data from that scope, and even modify that scope. There's no concept of a scope in React, mostly because React doesn't do dirty-checking like Angular, but also because React uses regular Javascript scoping to determine what variables/objects are available to the view. More on that later.
Templating
This is an important difference. In Angular you define your templates in either a different file, or as a Javascript string. In React, you define your view in Javascript or JSX. JSX is an XML/HTML like language extension to Javascript which lets you describe HTML (or native views, like in React Native).
In JSX, you can set property values on elements either as strings like <div className="myClass"> or with a Javascript expression, like this: <div className={myClassVariable}> where myClassVariable is a regular Javascript variable. Anything between { and } in JSX is just plain old Javascript. You can pass an object, a function, a string, etc. And your linter can help you when you try to use an undefined variable in JSX, which is something your linter can't do when you use attributes in Angular templates.
By defining your views in JSX instead of HTML strings, you have the full power of Javascript at your disposal. You don't need something like an Angular scope, because you already have a Javascript scope which determines what you can use in your view. This is the reason that getting good at Angular just makes you good at Angular, whereas getting good at React also makes you a better Javascript programmer.
Data binding/mutation/state
Angular uses scopes to define application state. That scope can be mutated either from a view, a controller or a directive. Scopes inherit from each other, so if you get access to a scope, you can also modify the parent scope. This is one of the reasons that big Angular applications tend to get difficult to manage, because the state of the application can be changed from a lot of places. And watches on those changes which triggers other changes makes it even harder to grasp.
React uses two concepts called props and state. Think of them like regular Javascript functions. State are variables defined in a function, and props are the arguments that are passed to functions.
Variables defined in a function can be changed in that function and they can be passed to other functions as arguments.
But arguments passed to a function should never be changed in the function that received them. They can make a local variable and assign its value to the arguments value and change that local variable. But it should never change the argument directly.
So props are values passed to a component from a parent component. The component receiving props doesn't own them, and don't know where they came from, much like arguments to a function. State on the other hand is owned by the component, and the component can change it in any way it wants much like the local variables.
React knows when state and props of a component change since you have to explicitly call setState when you want to change the state of a component. It knows when props change because you pass props to a component when the parent component renders.
When the state is changed, React re-renders the component (and all of its child components). Note that it only re-renders them to a virtual representation of the components. It then performs a diff on what has changed since the last render, and only the actual changes are applied to the DOM. This is essentially the secret sauce of React. The programming model is to re-render everything everytime something happens, but only doing the minimal amount of work needed.
Where are my controllers!?
Like I said, React doesn't have any concept of a controller, it only focus on components. That said, you often still use a controller/view separation when you use React. You have components (sometimes called view controllers) that handle data fetching and state management, but do very little rendering. Instead, you have a separate component that knows very little about data fetching and a lot about rendering. So the view controller component knows how to fetch data, and it then passes that data on the component that knows how to render it. A simple example is something like this:
var TodoItemsComponent = React.createClass({
getInitialState: function () {
return {
todoItems: null
}
},
componentDidMount: function () {
var self = this;
TodoStore.getAll().then(function (todoItems) {
self.setState({todoItems: todoItems});
});
TodoStore.onChange(function (todoItems) {
self.setState({todoItems: todoItems});
});
},
render: function () {
if (this.state.todoItems) {
return <TodoListComponent todoItems={this.state.todoItems} />;
} else {
return <Spinner />;
}
}
});
var TodoListComponent = React.createClass({
render: function () {
return (
<ul>
{this.props.todoItems.map(function (todo) {
return <li>{todo.text}</li>;
})}
</ul>
);
}
});
In this example, there's two components. One which is only concerned about data fetching, and one which is only concerned about rendering. They're both React components, but they have very different responsibilities. This is the separation that controllers and directives have in Angular, but React doesn't force you into it.
Data binding
Angular uses data binding to keep the view in sync with the view model. React doesn't use data binding at all. You could say that Angular monitors the view model for changes and updates the DOM accordingly, whereas React monitors the JSX you return from your components for changes, and updates the DOM accordingly.
Separation of concerns
A lot of people are skeptical of React because they feel that React doesn't separate concerns in a good way. And JSX is often the target of that argument. They feel like putting markup in your Javascript is mixing concerns about the view and the behaviour. If your used to Angular, you probably don't agree that describing behaviour in your markup is a bad idea (since you do that in Angular as well). An often touted counter argument is that React "separates concerns, not technologies" in that the view (markup) and the behaviour of it are not separate concerns but just traditionally separate technologies (HTML and Javascript). By co-locating the behaviour and the markup, you get quite a few benefits:
It's easy to see if you have unused variables or functions. With Angular, you have to look in the template for expressions, and hunt down all places that have access to that scope to see if there are variables or functions on the scope that aren't used.
A component becomes isolated to one file, and you don't have to switch back and forth between a Javascript file and a template file.
A change to the behaviour often requires a change to the markup, and vice versa. So keeping it inside one file makes it easier to see what changes are needed.
This turned out to be a wall-of-text, so please let me know if there's something I should clarify or expand upon.
ReactJS is all about (reusable) components, which imo can best be compared to Angular's directives.
So I would say, imagine creating an app in AngularJS with only directives :)
I started developing in ReactJS a few weeks ago and at first it was strange (writing template code in your JS, wtf?), but now I got used to it. I recently also started playing with React-Native and it is awesome!
I could list a lot of differences between Angular and React here now, but there are some nice articles written by others on that already, so I recommend you to read those to get a clearer idea.
React.js and How Does It Fit In With Everything Else?
AngularJS vs ReactJS for large web applications
Coming to React from Angular
From angular to react # Reddit
and then there is also awesome-react, a compilation of react libraries, resources, tutorials, articles (you name it, it's there)
Related to your question, this section is probably the most interesting for you:
More articles on the approach of ReactJS and comparisons with other frameworks
Related
I just started learning Vue and Vuex. I saw that I have the same code in different components. I started using Vuex and i store my data inside index.js and it's really helpful.
My questions is, how can I store click functions with vuex. In the code below is simple example
<button #click="clickMe">Click Me</button>
methods: {
clickMe() {
console.log('Hellouu')
},
}
Keeping the logic of a component in itself is what component-based approach is about. A click listener on a component or its sub-element is very personal and private to a component.
Mixins
But.. let's say you have a situation where you have the same exact logic that needs to be executed on-click on multiple components, the answer will be to use mixins. Store is not the place to do it. This holds and is true for any case where you need to 'share reusable functionalities'.
Apart from providing flexibility, mixins have a number of benefits, for instance, you can take advantage of the option merging rules within mixins to override the onClick() method described in a mixin to cater for a special case within one of the components, but continue to use the rest of the common logic the mixin contains.
Note: Be careful though, Hook functions with the same name are instead merged into an array so that all of them will be called. Mixin hooks will be called before the component’s own hooks.
Read more (optional)
As a great real world example check out this repository: https://github.com/buefy/buefy. Its a UI components library that is built with Vuejs. You can find many more examples and best practices in such open source repositories and these are always a great reference point for writing better code.
The offical RFC
There is a example for effect
function createSharedComposable(composable) {
let subscribers = 0
let state, scope
const dispose = () => {
if (scope && --subscribers <= 0) {
scope.stop()
state = scope = null
}
}
return (...args) => {
subscribers++
if (!state) {
scope = effectScope(true)
state = scope.run(() => composable(...args))
}
onScopeDispose(dispose)
return state
}
}
I know what it will do, it will force all components to calculate only once when we use useMouse API
But I can't understand the concept of effect, and how does it work?
Espeically some APIs for effect like getCurrentScope. I tried to see the return values of getCurrentScope, but i have gained nothing.
Please help me!
effect is a common term used in reactive frameworks (both VueJS and React) to refer to (I believe) side effect. If you are familiar with functional programming, you probably already know that it is called side effect because it is not "pure function", because it mutates shared or global state.
Ignore the academic terminology, effect in these systems merely refers to any application defined method that does something bespoke, like
const foo = () => {
// I do something bespoke
}
The meaning of effect is really that broad. What your method actually does in its body does not matter to the framework. All that the framework knows is foo does some unstructured things. What VueJS does in extra, is to monitor, through its reactivity system, if your effect depends on any reactive data. And if it does, VueJS will re-run your effect every time the data it depends on changes.
effect (or side effect) isn't something bad or special or advanced. In fact, your application is all about making effects/side effects. For example, the commonest effect in a VueJS application is DOM manipulation. It is so common that VueJS extracts it into a different abstraction: template. Behind the scene, templates are compiled to render functions - which look a lot like the foo above - that get re-evaluated every time some dependent reactive data changes. That is how VueJS keeps your UI up to date.
Another extreme of common effects are those really bespoke ones, e.g. you just want to do some old fashion imperative things (like the jQuery style) whenever your data changes. And VueJS let you do it through watchEffect: you give VueJS a lambda, and VueJS will blindly call it every time its dependency changes without asking what it is doing.
VueJS discovers your dependency on reactive data by running your effect. As long as your effect accesses any reactive data (say, yourState.bar) during its execution, VueJS will notice that and record a dependency of your effect on yourState.bar
In its essence, the reactivity system is just the modern version of the good-old observable/subscriber pattern. Reactive states are the observables, and effects are the subscribers/observers. If you look beyond the magic layer and think of VueJS in the form of a subscriber pattern, there is one issue it cannot avoid: whenever you have subscribe, you will have to deal with unsubscribe, otherwise you will have memory or resource leaks simply because you keep holding on to subscribers (they in turn hold on to other things) and nothing can be freed. This unsubscribe part is what the RFC calls "effect dispose".
Typically you will have two challenges when dealing with this unsubscribing/disposing/cleaning up/cancelling business:
deciding when to unsubscribe/dispose
knowing how to unsubscribe/dispose
In a typical reactive framework, both of the above are application's responsibility. As the application dev, you are the only one who knows when a subscription is no longer needed and how to reverse the additional resource allocation (if any) you made at the time of creating the subscription.
But in a typical VueJS app you rarely need to manually deal with any kind of cleanup (stopping the DOM patching, watch, or computed etc). That is because VueJS takes care of it automatically. The reactive effects established within a component's setup method will be automatically disposed (whatever needed for a proper clean up) when the component is unmounted. How does that happen? Let's just say some other magic exists inside VueJS to associate all your effects with the life cycle of the corresponding component. Technically, as the RFC says, that magic is effectScope.
Conceptually, each component creates an effectScope. All your effects defined inside component setup method will be associated with that scope. When the component destroys, VueJS automatically destroys the scope, which will clean up the associated effects.
The RFC proposes to make effectScope a public api so that people can use it without using a VueJS component. This is possible because Vue3 is built with modularization. You can use Vue's reactivity module without using the entire VueJS. But without the underlying effectScope, you then have to manually dispose all your effects.
What would making a coffee look like in code?
snowingfox.getCupsOutOfCupboard();
snowingfox.getCoffeeOffShelf();
snowingfox.getMilkOutOfFridge();
snowingfox.boilingWater();
// ...
Now imagine each morning I wake up and have a coffee. You could say I'm making
a coffee in reaction to waking up. How would I run this code repeatedly in
response to an isMorning variable becoming true?
This is what effect solves in Vue 3. It wraps around a chunk of
code that should be executed in response to reactive data being changed. In practise you most likely won't use effect directly, and instead rely on
things like computed and watchEffect (which use effect in their
implementations).
In short: effect is one part of Vue's reactivity system and is Vue's way of
marking and locating code that should be re-run in response to data updates.
Docs: https://v3.vuejs.org/guide/reactivity.html
Course: https://www.vuemastery.com/courses/vue-3-reactivity/vue3-reactivity/
Here's how the initial code could be implemented to be reactive:
import { ref, watchEffect } from 'vue';
const isMorning = ref(false);
watchEffect(() => {
if (!isMorning.value) return;
snowingfox.getCupsOutOfCupboard();
snowingfox.getCoffeeOffShelf();
snowingfox.getMilkOutOfFridge();
snowingfox.boilingWater();
});
I am making a WYSIWYG editor on the client side, with a toplevel NewProjectContainer render function that is:
render () {
return (
<div className="blog-post">
<TitleContainer user={this.props.user}/>
<ContentContainer user={this.props.user}/>
</div>
)
}
Both the TitleContainer and ContentContainer can be edited, and should be saved to both local storage, and when unmounted, save to backend db. Currently each component has its own saveLocal and saveDb function which is clearly an antipattern. Ideally the child nodes should hand over their content to the parent node NewProjectContainer, which then should handle the save logic. Does React agree this is the "sane" way to do things? if so are there language constructs (i'm new here) in React that facilitate this? The simplest way is to pass a function down as props, but this smells weird, am I wrong here?
One of the pitfalls you want to avoid is to have your state spread out throughout your app.
Here is what I suggest:
Start by having the entire app state inside NewProjectContainer and passing down functions and properties as props. Ideally TitleContainer and ContentContainer would be pure components meaning that they don't have their own react state (this.state). You would then separate all the API calls and business logic inside your parent container and use the children for display only.
Once your app grows beyond 3 components, you might want to look at a state management solution. The most popular are redux and mobx. There are plenty of tutorials online on how to get started with these. These libraries will help you structure the way you handle state and side effects (API calls and other async operations)
When I'm sharing data among components should I call that data only once and provide it as #Input() or should I call that data again on every component's cycle?
For example, I have the following components in one page:
<game-info [id]="params?.id"></game-info>
<game-leaderboard [uid]="auth" [id]="params?.id"></game-leaderboard>
<game-progress [uid]="auth" [id]="params?.id"></game-progress>
Where I get the id from the ActivatedRoute and the uid from my authentication service. In some cases, I'm also passing a data input for multiple components in the same page.
One problem I face is that, sometimes, I'm passing data to many children components and it was harder to debug. For example:
game.component.html
<game-details [data]="data"></game-details>
<game-progress [data]="data"></game-progress>
Then, on details.component.html, I'd pass data as an input to another component - and so on. It became a really long chain:
<game-info [data]="data"></game-info>
<game-players [id]="(data | async)?.$key></game-players>
Is it a proper approach? Or would it be better to get those parameters inside of every component?
Another issue, for example, sometimes I need to get the an async parameter (e.g. uid from an Observable) during onInit but it didn't receive it yet. So, I was wondering if I should just call those parameters straight in the component instead of passing them as an input.
PS. I'm not sure if this is off-topic. If so, please feel free to remove it.
Nothing wrong with that approach. Actually, this is 1 of the recommended ways nowadays where your top-level 'smart' components would gather the data and then inject that data to your 'presentational' aka 'view' aka 'dumb' components. Note that data also flows the other way around: all Events are emitted upwards, where they are handled by the containing 'smart' component. See here for a good (better) explanation.
I must say this approach has been working very well for me: code is clean (clear responsibilities, reusability and testability of presentational components...) although I must admit I share your concern that it might become a bit tedious when you have quite a lot of nested components.
A common approach would be using it as a Injectable service.
For its benefits, as it says:
The component can create the dependency, typically using the new
operator. The component can look up the dependency, by referring to a
global variable. The component can have the dependency passed to it
where it is needed.
For angular 1, check https://docs.angularjs.org/guide/di
For angular 2, check the first answer in What's the best way to inject one service into another in angular 2 (Beta)?
It is hard to answer the question since I am not sure exactly what you are trying to achieve but it might be worth looking into services. Services will have one shared space for the components under the component it is declared under(example the app.component or even app.mudule). Then you can pass the new parameters to other components through the service. That would be the proper way of having a shared state and you can pass through many components by just injecting the service.
The following is from an issue I posted on EmberJS GitHub, but Stack Overflow is better suited for a discussion than GitHub.
I am building a few complex components at the moment including composite components and I hit a roadblock with the extreme isolation components live in.
There are several cases where I don't need the components to trigger an action on a controller, but where a controller needs to trigger a behaviour change on the component.
Problems is that the components don't know about the controller and the controller is not creating the components either: they are defined in a template.
I kind of solved the problem by subclassing the Ember.Component class to offer a way for messages to get through components.
The new component subclass breaks the on purpose isolation of components that shouldn't know about the outer controller.
The 2 less invasive options I found to make component methods calls from outside are:
Cache component / name of instance pairs in a global array like
App.components, then call a component method with
App.components['name'].method()
Trigger events from outside, register and handle them in the
components. However in that case I am passing an eventSource object
to the component, often a controller like so: {{my-component
eventSource=controller}}
My question is about how could we solve this problem in the most elegant and less invasive way possible for components ?
For achieving composite components, using the components like lego pieces, it seems impossible to me at the moment to see how we can achieve that goal without breaking the components isolation.
Any input, ideas, solutions, discussion is very welcome.
Note: By the way, the first method that breaks the component isolation is inspired by the work done on the ember-bootstrap components: https://github.com/ember-addons/bootstrap-for-ember
The author had to solve the same problem of being capable of triggering methods inside the components from outside.
Another note: Just for the record, another way to access a component is to use Ember.View.views['name'] where name is a view name you gave to your component. However I feel dirty to make such calls, even more from a controller.
In general, I would try to solve this by binding properties to your component, which could then change according to computed properties or observers based on those properties.
For instance, instead of trying to call a method like deactivate on a component, bind a property such as active to a property in the template:
{{my-component active=formEnabled}}
I'm hesitant to recommend passing an eventSource to components as a general solution (like your {{my-component eventSource=controller}} example). I imagine this could work with a class or mixin that just emits specific events and is tightly coupled with your component, but I'm struggling to come up with a use case that justifies this approach.