July 30, 2020
Introduction to react for angular developers Part 1
You are an angular developer, but now you are getting a little bit confused, because everyone is talking about something called react? So take a look at this short practical comparison of these two big Frameworks and get an impression of the differences and similarities. Following, we will create the same app in both of these frameworks to work out the differences. What kind of app could be better to show that? Exactly it’s going to be a classical todo-app :).
We will focus on functional components in react and we will not discuss the old-fashioned react class approach.
Another Todo-App
Create a new App
The angular way: we need the angular cli installed globally. To create a new app we would use something like ng new my-todo-app.
The react way: there is no special react cli, we just need node to create our app. npx create-react-app my-todo-app. If we want to use react with typescript as default language, we have to add a flag: npx create-react-app my-todo-app –template typescript.
Run the app locally
The angular way: ng serve
The react way: react-scripts start
In both applications the default command is stored as npm start in the package.json.
Create a component:
Both of these frameworks generally have a component based approach of structuring the web application. The idea is to organise the view in small, decapsulated parts that can be reused without having confusing dependencies. Of course there are different ways to create a component.
The angular way: ng generate component my-card.
The react way: Create a file named my-card.tsx manually. Then code your component:
1 2 3 4 5 |
import React from 'react'; export default function MyCard() { return (<div> My Card </div>); } |
As mentioned before, we are using functional components. That means our component is actually just a function. We return our html (it is no real html, it is jsx, but at first glance it looks like html).
If you are not familiar with default take a look here. It is not mandatory to use, but this will make the code clearer.
The module system:
The angular way: Register the component on the associated module.
The react way: There is no complex module system. Just import and use the component whereever you need it.
1 2 3 4 5 6 7 8 9 10 11 |
import React from 'react'; import './App.css'; import MyCard from './my-card'; function App() { return ( <MyCard></MyCard> ); } export default App; |
Store data in the component
In our todo-app we want to create an add-button, for adding todos. Each todo is represented by a my-card component. A todo has a checkbox and a description. We want to save all todo informations in the parent component.
The angular way: First of all we create a todo array like todos: Todos = []. To get access to the data of the input and the checkbox field we use either a formcontrol or the ngModel. By clicking on the add button we push the new todo object in our todos array.
The react way: In react we make use of the useState Hook. We save the data in the state of our App.tsx component. This applies for the data of a new todo and for the array of all todos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
export interface Todo { text: string; checked: boolean; } export interface TodosState { newTodo: Todo; todos: Todo[]; } function App() { const [todoState, setTodoState] = useState<TodosState>( { newTodo: { text: '', checked: false, }, todos: [] } ); function inputChanged(evt: SyntheticEvent) { setTodoState({ ...todoState, newTodo: {...todoState.newTodo, text: (evt.target as HTMLInputElement).value} }); } function checkboxChanged(evt: SyntheticEvent) { setTodoState({ ...todoState, newTodo: {...todoState.newTodo, checked: (evt.target as HTMLInputElement).checked} }); } function addTodo() { setTodoState({newTodo: {text: '', checked: false}, todos: [...todoState.todos, todoState.newTodo]}) } return ( <div> <input type="text" onChange={inputChanged} value={todoState.newTodo.text}/> <input type='checkbox' onChange={checkboxChanged} checked={todoState.newTodo.checked}/> <button onClick={addTodo}> Add todo</button> </div> ) } export default App; |
The whole state of the componentent consists of a new todo (the current value of the input and checkbox) and of all existing todos. Changes within the input leads to changes in the state of the component. Clicking the add button also chaning the state of the component.
Passing data from parent to child:
To make clear how to pass data from a parent component to a child component, let’s create an easy example. By default lets show an example todo card.
The angular way: In our child component we create an Input() todo: Todo variable. In our parent component we pass a todo object to our child component like <my-card [todo]=”{text: ‘example’, checked: false}”></my-card>
The react way: In our parent component we pass the example todo to the child component:
1 |
<MyCard todo={{text:'', checked: false}}></MyCard> |
In our child component we handle the example todo as props and just display them on our site for the moment.
1 2 3 4 5 6 7 8 9 |
import React from 'react'; export default function MyCard(props: any) { return (<div> {props.todo.text} {props.todo.checked} </div>); } |
Directives:
React does not know the system of directives. Let’s look at a specific problem to see how react solves such “directive-problems”. We want to display all todos from the array. Furthermore we only want to show todos, that are not checked yet. So we need a way to hide all done todos.
The angular way: We can iterate via *ngFor (in our html code) over the array and display the todos. We would use a *ngIf to show or hide a todo, depending on the status of the checkbox.
The react way: Our return statement of the App.tsx looks like this:
1 2 3 4 5 6 7 8 9 |
return ( <div> <input type="text" onChange={inputChanged} value={todoState.newTodo.text}/> <input type='checkbox' onChange={checkboxChanged} checked={todoState.newTodo.checked}/> <button onClick={addTodo}> Add todo</button> <MyCard todo={{text:'example', checked: false}}></MyCard> {todoState.todos.map((todo, index) => !todo.checked && <MyCard todo={todo} key={index}></MyCard>)} </div> ) |
We loop with the java script map function over all todos and we use the logic &&-operator to only display the cards with “checked == false”. We need to add the key property to avoid console warnings.
Conclusion
You can see that both frameworks have a similar component-based approach. The communication between parent and child component is syntactically different, but in principle there are obvious parallels. To store data in react you have to use the state or the props of a component. In Angular you can create variables where ever you want in the component. In general angular has the stricter structure with the .ts, .html and .css file.
It seems like react is bringing the html in javascript, in the opposite angular is bringing the javascript into html.
For more differences and similarities take a look at Part 2 of this introduction. We will discuss the differences in the Lifecycle, styling, and much more. (Coming soon)