https://github.com/alexander-schranz/twig-for-react-devs
Twig for react devs. A guide to get react developers faster into the twig template engine.
https://github.com/alexander-schranz/twig-for-react-devs
alexander-schranz-article reactjs symfony twig
Last synced: 11 months ago
JSON representation
Twig for react devs. A guide to get react developers faster into the twig template engine.
- Host: GitHub
- URL: https://github.com/alexander-schranz/twig-for-react-devs
- Owner: alexander-schranz
- License: mit
- Created: 2021-02-08T17:56:54.000Z (about 5 years ago)
- Default Branch: main
- Last Pushed: 2021-02-10T10:47:43.000Z (about 5 years ago)
- Last Synced: 2025-03-29T23:41:17.583Z (12 months ago)
- Topics: alexander-schranz-article, reactjs, symfony, twig
- Homepage:
- Size: 54.7 KB
- Stars: 22
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Twig for react devs
An easy guide for react developers getting into PHP Twig template engine from Symfony.

## Introduction
Hello 👋,
My name is Alexander Schranz ([alex_s_](https://twitter.com/alex_s_)) and I'm fulltime Webdeveloper
working on the [SULU CMS](https://sulu.io/?utm_source=github&utm_medium=repository&utm_campaign=alex-twig-for-react-devs)
and did based on that created a lot of websites.
With this article I wanted to make it easier for React Developers
getting into the Twig Syntax.
Every Section will first Provide the `React JS` ⚛️ code and then the `Twig` 🌱
followed by explanation about the difference between them.
At the start I want to mention here that `Twig` was inspired a lot by
[Jinja2 Template Engine](https://github.com/pallets/jinja)
developed for the Django Python Framework, but was improved
over the years with other new features by the Symfony Team.
Before continue with the overview the best comparison is
what `JSX` is for `React` (JS), `Twig` is for `Symfony` (PHP).
So all Business Logic should live outside of it.
**Table of Contents**
- [Outputting a variable](#outputting-a-variable)
- [Outputting raw HTML](#outputting-raw-html)
- [If statements](#if-statements)
- [Loops](#loops)
- [Base Template](#base-template)
- [Providing props to templates](#providing-props-to-templates)
- [Include and override parts](#include-and-override-parts)
- [Dynamic Include](#dynamic-include)
- [Conclusion](#conclusion)
## Outputting a variable
In the first example we will to the most simpliest thing just
outputting a variable we did create in our component / template.
### Outputting a variable (React JS ⚛️)
```js
// src/views/My.js
import React from 'react';
class My extends React.Component {
render() {
const title = 'My Title';
return
{title}
;
}
}
```
### Outputting a variable (Twig 🌱)
```twig
{# templates/pages/my.html.twig #}
{% set title = 'My Title' %}
{{ title }}
```
### Outputting a variable (Explanation)
Outputting a variable in Twig and JSX is very similar instead
of `{variable}` you use `{{ variable }}`. The spaces are optional
but recommended by the [Twig coding standards](https://twig.symfony.com/doc/3.x/coding_standards.html).
## Outputting raw HTML
There are cases where you use CKEditor or other rich text editors
to create content which will provide you raw HTML code you would
like to render in this case you want not that your variable you
want to outputted does get escaped.
### Outputting raw HTML (React JS ⚛️)
```js
// src/views/My.js
import React from 'react';
class My extends React.Component {
render() {
const someHtml = '
My Text editor content
';
return
;
}
}
```
### Outputting raw HTML (Twig 🌱)
```twig
{# templates/pages/my.html.twig #}
{% set someHtml = '
My Text editor content
' %}
{{ someHtml|raw }}
```
### Outputting raw HTML (Explanation)
Both (`React JS` and `Twig`) escape variables by default so no HTML
injected without a call of an additional prop or filter.
There are in Twig other ways to disable `autoescape` over a whole
content. See for this the [official Twig Docs](https://twig.symfony.com/doc/3.x/api.html#escaper-extension).
I personally recommend only using the `|raw` filter todo this kind
of things.
## If statements
### If statements (React JS ⚛️)
```js
// src/views/My.js
import React from 'react';
class My extends React.Component {
render() {
var title = 'Test' ;
const list = ['Test', 'Test 2'];
// Basic equal if statement
if (title == 'test') {
title = 'Basic equal if statement';
// Not equal if statement
} else if (title != 'test') {
title = 'Not equal if statement';
// Typesafe if statemenet
} else if (title === false) {
title = 'Typesafe if statemenet';
// Typesafe not if statemenet
} else if (title !== false) {
title = 'Typesafe not if statemenet';
// In array if statemenet
} else if (list.includes(title)) {
title = 'In array if statemenet';
// Not in array if statemenet
} else if (!list.includes(title)) {
title = 'Not in array if statemenet';
// Greater if statement
} else if (title > 10) {
title = 'Greater if statement';
// And if statement
} else if (title > 10 && title < 10) {
title = 'And if statement';
// Or if statement
} else if (title > 10 || title != 0) {
title = 'Or if statement';
// Else if statement
} else {
title = 'Else if statement';
}
return
{title}
{title ? title : 'Other'}
;
}
}
```
### If statements (Twig 🌱)
```twig
{# templates/pages/my.html.twig #}
{% set title = 'Test' %}
{% set list = ['Test', 'Test 2'] %}
{# Basic equal if statement #}
{% if title == 'test' %}
{% set title = 'Basic equal if statement' %}
{# Basic not equal if statement #}
{% elseif title != 'test' %}
{% set title = 'Basic not equal if statement' %}
{# Typesafe if statement #}
{% elseif title same as(false) %} {# Very uncommon in Twig todo typesafe checks #}
{% set title = 'Typesafe if statement' %}
{# Typesafe not if statement #}
{% elseif title not same as(false) %} {# Very uncommon in Twig todo typesafe checks #}
{% set title = 'Typesafe not if statement' %}
{# In array if statement #}
{% elseif title in list %}
{% set title = 'In array if statement' %}
{# Not in array if statement #}
{% elseif title not in list %}
{% set title = 'Not in array if statement' %}
{# Greater if statement #}
{% elseif title > 10 %}
{% set title = 'Greater if statement' %}
{# And if statement #}
{% elseif title > 10 and title < 10 %}
{% set title = 'And if statement' %}
{# Or if statement #}
{% elseif title > 10 or title != 0 %}
{% set title = 'Or if statement' %}
{# Else if statement #}
{% else %}
{% set title = 'Else if statement' %}
{% endif %}
{{ title }}
{{ title ?: 'Other' }}
```
### If statements (Explanation)
For if statement the [if tag](https://twig.symfony.com/doc/3.x/tags/if.html)
is used. Where in JavaScript it is very common to have
typesafe check with `===`. This is very uncommon in twig
because Twig is really focused being a template engine and
not a language where you should build business logic.
It is still possible in Twig doing a typesafe check using
the [same as test](https://twig.symfony.com/doc/3.x/tests/sameas.html).
Twig like PHP supports also the ternary operator (`?:`) and the
null-coalescing operator (`??`). Read more about them in the
[Twig operators documentation](https://twig.symfony.com/doc/3.x/templates.html#other-operators).
## Loops
### Loops (React JS ⚛️)
```js
// src/views/My.js
import React from 'react';
class My extends React.Component {
render() {
const list = [{
title: 'List Item 1',
}, {
title: 'List Item 2',
}];
return
-
{item.title}
;
{list.map((item) => {
return
})}
}
}
```
### Loops (Twig 🌱)
```twig
{# templates/pages/my.html.twig #}
{% set list = [
{
title: 'List Item 1',
},
{
title: 'List Item 2',
}
] %}
- {{ item.title }}
{% for item in list %}
{% endfor %}
```
### Loops (Explanation)
Where in `JavaScript` different way of looping exist in twig
you will work with the [for](https://twig.symfony.com/doc/3.x/tags/for.html)
to loop over variables.
Twig here supports some range function to make developing of
templates easier for example:
```twig
{# Output numbers from 0 - 10 #}
{% for i in 0..10 %}
* {{ i }}
{% endfor %}
{# Output letters from a-z #}
{% for i in 'a'..'z' %}
* {{ i }}
{% endfor %}
{# Output letters from A-Z #}
{% for letter in 'a'|upper..'z'|upper %}
* {{ letter }}
{% endfor %}
```
By default inside the `for` loop Twig provide some magic variable
called `loop` which will provide you the following data:
```twig
{% for i in 0..10 %}
{{ loop.index }} {# index beginning with 1 #}
{{ loop.index0 }} {# index beginning with 0 #}
{{ loop.revindex }} {# reverted index #}
{{ loop.revindex0 }} {# reverted index0 #}
{{ loop.first }} {# boolean flag if its the first item of this loop #}
{{ loop.last }} {# boolean flag if its the last item of this loop #}
{{ loop.length }} {# the number of items of this loop #}
{{ loop.parent }} {# access the parent loop variable if using nested loops #}
{% endfor %}
```
Where in `React JS` you maybe need a `counter` or accessing the length
in `Twig` the `loop` variable is available inside every loop and make
it easy to add CSS classes to first or last items of a loop.
See here also the Twig documentation about the [for](https://twig.symfony.com/doc/3.x/tags/for.html)
tag.
As `React JS` has access to all `JavaScript` array available function
Twig also has it tricks to make outputting of html very simple.
So for example let see that we have variable which content is the
following:
```js
["1", "2", "3", "4", "5"]
```
and we want to render the following HTML:
```html
1
2
3
4
5
```
This can in Twig easily be rendered by the `batch` function
the following way:
```twig
{% for row in list|batch(3, '') %}
{% for item in row %}
{{ item }}
{% endfor %}
{% endfor %}
```
Read here also the offical documentation about the
[Twig batch function](https://twig.symfony.com/doc/3.x/filters/batch.html).
## Base Template
The first you mostly create when building a website is a base
template or base component which contains all things which your
templates have in common like Navigation, Footer, Header.
### Base Template (React JS ⚛️)
In react for rendering anything we first need to create a
`index.html` where the react application is started which also
contains the minimal required html for a page.
```html
```
In react a base template could look like the following.
```js
// src/views/Base.js
import React from 'react';
import Head from 'next/head'
import Navigation from './components/Navigation';
import Header from './components/Header';
import Footer from './components/Footer';
class Base extends React.Component {
render() {
const {
header
} = this.props;
const headerComponent = header ? header : ;
return
{this.props.title}
{this.props.children}
}
}
```
A default template build on top of the base template will look like the following way:
```js
// src/views/Default.js
import React from 'react';
import Base from './components/Base';
class Default extends React.Component {
render() {
const title = 'Some Title';
return
{title}
;
}
}
```
A homepage template build on top of the base template could look this way
which will override the Header component:
```js
// src/views/Homepage.js
import React from 'react';
import Base from './components/Base';
import HeaderBig from './components/HeaderBig';
class Homepage extends React.Component {
render() {
const title = 'Some Title';
return }>
{title}
;
}
}
```
This way we created a reusable base which can be used in all components again.
### Base Template (Twig 🌱)
To implement the same as we did above we need to create the following
in our Twig structure. As Twig is server rendered by PHP in Symfony
we will create the `base.html.twig` which will contain the html which
was in react rendered by `index.html` and `Base.js`.
```twig
{# templates/base.html.twig #}
{title}
{% include 'include/navigation.html.twig' %}
{% block header %}
{% include 'include/header.html.twig' %}
{% endblock %}
{% block content %}{% endblock %}
{% include 'include/footer.html.twig' %}