ReactJS talks to your API

Remove the link. In base.html.twig, we already have a few JavaScript files that are included on every page. But now, I want to include some JavaScript on just this page - I don't need this stuff everywhere.

Page-Specific JavaScript (or CSS)

Remember from earlier that those script tags live in a javascripts block. Hey, that's perfect! In the child template, we can override that block: {% block javascripts %} then {% endblock %}:

38 lines app/Resources/views/genus/show.html.twig
... lines 1 - 23
{% block javascripts %}
... lines 25 - 36
{% endblock %}

Now, whatever JS we put here will end up at the bottom of the layout. Perfect, right?

No, not perfect! When you override blocks, you override them completely. With this code, it will completely replace the other scripts in the base template. I don't want that! I really want to append content to this block.

The secret awesome solution to this is the parent() function:

38 lines app/Resources/views/genus/show.html.twig
... lines 1 - 23
{% block javascripts %}
{{ parent() }}
... lines 26 - 36
{% endblock %}

This prints all of the content from the parent block, and then we can put our cool stuff below that.

Including the ReactJS Code

Here's the goal: add some JavaScript that will make an AJAX request to the notes API endpoint and use that to render them with the same markup we had before. We'll use ReactJS to do this. It's powerful... and super fun, but if it's new to you, don't worry. We're not going to learn it now, just preview it to see how to get our API working with a JavaScript frontend.

First, include three external script tags for React itself. Next, I'm going to include one more script tag that points to a file in our project: notes.react.js:

38 lines app/Resources/views/genus/show.html.twig
... lines 1 - 23
{% block javascripts %}
{{ parent() }}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.3/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
<script type="text/babel" src="{{ asset('js/notes.react.js') }}"></script>
... lines 31 - 36
{% endblock %}

Let's check that file out! Remember, it's in web/js/notes.react.js:

69 lines web/js/notes.react.js
var NoteSection = React.createClass({
getInitialState: function() {
return {
notes: []
}
},
componentDidMount: function() {
this.loadNotesFromServer();
setInterval(this.loadNotesFromServer, 2000);
},
loadNotesFromServer: function() {
$.ajax({
url: '/genus/octopus/notes',
success: function (data) {
this.setState({notes: data.notes});
}.bind(this)
});
},
render: function() {
return (
<div>
<div className="notes-container">
<h2 className="notes-header">Notes</h2>
<div><i className="fa fa-plus plus-btn"></i></div>
</div>
<NoteList notes={this.state.notes} />
</div>
);
}
});
var NoteList = React.createClass({
render: function() {
var noteNodes = this.props.notes.map(function(note) {
return (
<NoteBox username={note.username} avatarUri={note.avatarUri} date={note.date} key={note.id}>{note.note}</NoteBox>
);
});
return (
<section id="cd-timeline">
{noteNodes}
</section>
);
}
});
var NoteBox = React.createClass({
render: function() {
return (
<div className="cd-timeline-block">
<div className="cd-timeline-img">
<img src={this.props.avatarUri} className="img-circle" alt="Leanna!" />
</div>
<div className="cd-timeline-content">
<h2><a href="#">{this.props.username}</a></h2>
<p>{this.props.children}</p>
<span className="cd-date">{this.props.date}</span>
</div>
</div>
);
}
});
window.NoteSection = NoteSection;

The ReactJS App

This is a small ReactJS app that uses our API to build all of the same markup that we had on the page before, but dynamically. It uses jQuery to make the AJAX call:

69 lines web/js/notes.react.js
var NoteSection = React.createClass({
... lines 2 - 12
loadNotesFromServer: function() {
$.ajax({
url: '/genus/octopus/notes',
success: function (data) {
this.setState({notes: data.notes});
}.bind(this)
});
},
... lines 21 - 32
});
... lines 34 - 69

But I have a hardcoded URL right now - /genus/octopus/notes. Obviously, that's a problem, and lame. But ignore it for a second.

Back in the template, we need to start up the ReactJS app. Add a script tag with type="text/babel" - that's a React thing. To boot the app, add ReactDOM.render:

38 lines app/Resources/views/genus/show.html.twig
... lines 1 - 23
{% block javascripts %}
... lines 25 - 29
<script type="text/babel" src="{{ asset('js/notes.react.js') }}"></script>
<script type="text/babel">
ReactDOM.render(
... lines 33 - 34
);
</script>
{% endblock %}

PhpStorm is not going to like how this looks, but ignore it. Render the NoteSection into document.getElementById('js-notes-wrapper'):

38 lines app/Resources/views/genus/show.html.twig
... lines 1 - 31
ReactDOM.render(
<NoteSection />,
document.getElementById('js-notes-wrapper')
);
... lines 36 - 38

Back in the HTML area, clear things out and add an empty div with this id:

38 lines app/Resources/views/genus/show.html.twig
... lines 1 - 4
{% block body %}
... lines 6 - 20
<div id="js-notes-wrapper"></div>
{% endblock %}
... lines 23 - 38

Everything will be rendered here.

Ya know what? I think we should try it. Refresh. It's alive! It happened quickly, but this is loading dynamically. In fact, I added some simple magic so that it checks for new comments every two seconds. Let's see if it'll update without refreshing.

In the controller, remove one of the notes - take out AquaWeaver in the middle. Back to the browser! Boom! It's gone. Now put it back. There it is! So, really cool stuff.

Generating the URL for JavaScript

But... we still have that hardcoded URL. That's still lame, and a problem. How you fix this will depend on if you're using AngularJS, ReactJS or something else. But the idea is the same: we need to pass the dynamic value into JavaScript. Change the URL to this.props.url:

69 lines web/js/notes.react.js
var NoteSection = React.createClass({
... lines 2 - 12
loadNotesFromServer: function() {
$.ajax({
url: this.props.url,
... lines 16 - 18
});
},
... lines 21 - 32
});
... lines 34 - 69

This means that we will pass a url property to NoteSection. Since we create that in the Twig template, we'll pass it in there.

First, we need to get the URL to the API endpoint. Add var notesUrl = ''. Inside, generate the URL with twig using path(). Pass it genus_show_notes and the genusName set to name:

40 lines app/Resources/views/genus/show.html.twig
... lines 1 - 23
{% block javascripts %}
... lines 25 - 30
<script type="text/babel">
var notesUrl = '{{ path('genus_show_notes', {'genusName': name}) }}';
... lines 33 - 37
</script>
{% endblock %}

Yes, this is Twig inside of JavaScript. And yes, I know it can feel a little crazy.

Finally, pass this into React as a prop using url={notesUrl}:

40 lines app/Resources/views/genus/show.html.twig
... lines 1 - 33
ReactDOM.render(
<NoteSection url={notesUrl} />,
document.getElementById('js-notes-wrapper')
);
... lines 38 - 40

Try that out. It still works very nicely.

Go Deeper!

There is also an open-source bundle called FOSJsRoutingBundle that allows you to generate URLs purely from JavaScript. It's pretty awesome.

Congrats on making it this far: it means you're serious! We've just started, but we've already created a rich HTML page and an API endpoint to fuel some sweet JavaScript. And we're just starting to scratch the surface of Symfony.

What about talking to a database, using forms, setting up security or handling API input and validation? How and why should you register your own services? And what are event listeners? The answers to these will make you truly dangerous not just in Symfony, but as a programmer in general.

See you on the next challenge.

Leave a comment!

  • 2016-09-26 weaverryan

    Yea, we threw it in as an extra :) - there's definitely a lot more you need to know to actually use React (and jQuery would be a lot simpler for this use-case). But, really glad you liked the course, and thanks for the kind words - awesome!

    Cheers!

  • 2016-09-26 Maksym Minenko

    I'm not sure *at all* that this ReactJS lesson was needed at this stage, but in general I liked this course.
    And, Ryan, you do have a sense of humor. :) That's a gift in itself. :)
    Thank you.

  • 2016-09-23 weaverryan

    Awesome, my please :). In Drupal - as a random reference - you're able to (in PHP code) set data onto a PHP object, which is then exposed as a special JavaScript object called `drupalSettings` that is put on the Window variable. So, that's a similar idea to what you're talking about that's out in the wild already.

    Cheers!

  • 2016-09-22 Sebastián Poliak

    Ryan! Thank you for sharing this!

    Actually, the second option - in my opinion - is more cleanear than the first one. Maybe I try it in future code: we could create a Twig function to handle or *parse* the PHP variables into *windowed* JS variables...

    And with that we could use webpack too!

    Thank you again for your time, I'll bre browsing around ;)

  • 2016-09-21 weaverryan

    Yo Sebastián!

    Ah, cool! So, no, I'm not using any Twig loader with webpack - so there's nothing fancy going on between the JS and Twig in any way. In general, to pass variables from Twig to JS, I use two strategies:

    1) In "normal" JS, I usually turn the JS that's in my .js files into objects (or, at least, functions - but objects work nicely). Then, I instantiate these from Twig and pass in the variables. For example, imagine we have some ProductListWidget.js, which, maybe, displays a list of products in a carousel and also displays whether or not there is a current sale. Ultimately, my Twig JavaScript would be something like this (it's "faux code"):

    // in side a document.ready
    var productData = {{ productCollection|json }};
    var isCurrentSale = {{ isCurrentSale ? 'true' : 'false' }};

    var productListWidget = new ProductListWidget(
    productData,
    isCurrentSale
    );

    2) When I use webpack, where even the object instantiation itself is done inside an external JS file, I set window variables and read those from within my JS. However, I *only* read these window variables in *one* spot in my JS, and then I pass those variables around afterwards. I don't want to start having a bunch of buried window.VARNAME everywhere in my JS code :).

    window.productData = {{ productCollection|json }};
    window.isCurrentSale = {{ isCurrentSale ? 'true' : 'false' }};

    I hope this helps! You should be able to slowly extract the JS into external files, and then just pass in the dynamic data with a method similar to these.

    Cheers!

  • 2016-09-21 Sebastián Poliak

    Nice feedback. Currently we are using gulp, but we have a lot of twig files with javascript code and I doesn't like it.
    With webpack are you using any king of twig loader?
    In case we have to send php variables from twig to javascript, which is in your opinion the best way? Thats why we have javascript code in twig files.

  • 2016-09-21 weaverryan

    Hi Sebastián!

    Hmm, not really - the actual answer to this is to put it into an external JS file (which is much more proper anyways) and then minify/uglify that JS :). There are a lot of ways to handle that, of varying complexity, like Assetic (we talk about it in our Symfony 2 tutorial http://knpuniversity.com/scree..., Gulp (http://knpuniversity.com/scree... and also webpack, which we currently use on KnpU.com, but we don't have a screencast about this yet.

    Let me know if this helps!

  • 2016-09-21 Sebastián Poliak

    Hey! How can you minify or obsfuscate that javascript code living inside your twig file? Is there a tool or something?

  • 2016-09-12 weaverryan

    Awesome! That's the idea! The only problem is that you couldn't commit that and deploy it in real life - since you will probably deploy your site to myexamplesite.com (without any sub-directories) and thus *not* want these in that case. My solution *should* have made it work in all cases, by effectively adding the /aqua_note/web automatically, by detecting that you're using it as a sub-directory. But, no worries - I'm glad you got it working!

    Cheers!

  • 2016-09-08 Maxime Bonin

    The link was the issue : you were right !

    to fix this I've just completed the url with /aqua_note/web before the actual url.
    $notes = [
    ['id' => 1, 'username' => 'AquaPelham', 'avatarUri' => '/aqua_note/web/images/leanna.jpeg', 'note' => 'Octopus asked me a riddle, outsmarted me', 'date' => 'Dec. 10, 2015'],
    ['id' => 2, 'username' => 'AquaWeaver', 'avatarUri' => '/aqua_note/web/images/ryan.jpeg', 'note' => 'I counted 8 legs... as they wrapped around me', 'date' => 'Dec. 1, 2015'],
    ['id' => 3, 'username' => 'AquaPelham', 'avatarUri' => '/aqua_note/web/images/leanna.jpeg', 'note' => 'Inked!', 'date' => 'Aug. 20, 2015'],
    ];

    I couldn't get your code to work, though ...

    Everything works now : thanks :)

  • 2016-09-08 weaverryan

    Hey Maxime!

    Ah, sweet! This helps immensely. Here's the deal: IF you changed your site/webserver, so that the "web/" directory if your project were the document root, then it would work. In other words, if you changed your setup so that you could simply go to http://localhost/app_dev.php/genus/octopus. The problem is - and this is my fault for being lazy / not wanting to include some ugly details - that the JSON response (as you correctly printed in the img tag) returns simple /images/leanna.jpeg. But in *your* site, this means that it is looking for the image at http://localhost/images/leanna.jpeg - NOT http://localhost/aqua_note/web/images/leanna.jpeg (as it should be).

    The problem lies in the controller that returns the JSON: it should be returning "smarter" image paths. This is how you would do that:


    // in GenusController::getNotesAction()
    // ...

    $notes[] = [
    // .. all the other keys
    // change just avatarUri to be:
    'avatarUri' => $this->get('assets.packages')
    ->getUrl('/images/'.$note->getUserAvatarFilename()),
    ];

    This uses a "service" called assets.packages, which helps your image URLs be smarter. This will return a URL that looks like /aqua_note/web/images/leanna.jpeg: that service is smart enough to know that your site is under a "aqua_note/web" directory in your site.

    Let me know if that helps... and makes (some) sense!

    Cheers!

  • 2016-09-05 Maxime Bonin

    thanks for the quick reply Ryan !

    I can load Leanna's picture OK by going to this url : http://localhost/aqua_note/web/images/leanna.jpeg

    The 'website' is at : http://localhost/aqua_note/web/app_dev.php/genus/octopus (I use XAMPP)

    the 'inspect element' of the broken picture tells me this : <img class="img-circle" src="/images/leanna.jpeg" alt="Leanna!" data-reactid=".0.1.$1.0.0"><div></div></img>

  • 2016-09-05 weaverryan

    Hey Sheeran!

    Ah, awesome! I'm *thrilled* that these are useful (and fun!) for you - that's exactly what we're hoping for :).

    So hmm, let's figure out your issue :). First, when it doesn't work, do you see any JavaScript errors in your browser's console? And also, when you switch from the cdnjs URL to the js/browser.min.js version, you said that "it stops working ,but react... can be used locally". What do you mean by "can be used locally"?

    Let me know! And we'll find the problem.

    Cheers!

  • 2016-09-05 weaverryan

    Hey Maxime!

    Hmm, if you do an "Inspect element" on the broken images, you should be able to copy the image URL or open it in a new tab. I'd like to know *exactly* what URL is used when you try to do this. Also, If you go to the Octopus Genus page, what is the URL in your browser? Is it exactly http://localhost:8000/genus/octopus? Or is it something slightly different?

    I'm sure it's something minor with image paths - we'll be able to figure it out :).

    Cheers!

  • 2016-09-04 Maxime Bonin

    The notes load at the end of the page. But the pictures of Leanna and Ryan doesn't show. (only a caption saying "Leanna!")
    images like the octopus and the aquanaut are displayed just fine ...
    got the same 'notes.react.js' than the finish version code

  • 2016-09-04 Sheeran

    Hi, Ryan,

    Well done with your colleagues, as a foreigner I am quite impressed to these tutorials, so I am planning to have the subscription for further courses, that must be great fun!
    In the end of this episode, I run the course code perfectly ok, but when I downloaded the *react.js*, *react-dom.js* and *browser.min.js* to local machine, the dynamic effect and content doesn't exist anymore. I mean, the <div id="js-notes-wrapper"></div> part.
    After my testing, I noticed that, if I change:
    <script src="https://cdnjs.cloudflare.com/a..."></script>
    into
    <script src="{{ asset('js/browser.min.js') }}"></script>
    then it stops just working, but *react.js* and *react-dom.js* can be used locally.
    I am a newbie to this, so any advice or possible solutions will be appreciated!

    Best regards,
    Sheeran

  • 2016-07-14 Victor Bocharsky

    Hey Jade!

    Could you dump the `$variable` that you passing to the `persist()` method before the `$em->persist($variable);` line? It should be a valid Doctrine entity, but maybe you have some different object or even different type of this var here.

    Cheers!

  • 2016-07-13 Jade taboada

    i tried the code but no luck it still wont work. it is also happening on this line of code below.

    $em = $this->getDoctrine()->getManager();
    $em->persist($variable);
    $em->flush();

    hope you could help :D many thanks.

  • 2016-07-12 weaverryan

    Hi Jade!

    Ah, so your built-in web server is actually terminating! That's actually quite rare! Usually this only happens when there is a "segfault" - which is a result of a bug in PHP itself or because we're doing something *so* crazy that it's completely making PHP fall over :). In this case, I'm not sure what would be causing the problem. Try changing your code to the following. Does the built-in server still terminate?

    // return an empty JsonResponse
    return new JsonResponse([]);

    Also, this shouldn't cause the server to terminate, but make sure you have your "use" statement for the JsonResponse class.

    Cheers!

  • 2016-07-11 Jade taboada

    Hello Again,

    I just wonder this line "return new JsonResponse($data);" from getNotesAction function break the symfony itself by stoping the its service then gives me this error "Built-in server terminated unexpectedly". And nice tutz :D i love it.

  • 2016-07-11 Jade taboada

    TypeError: this.props.notes is undefined

  • 2016-06-30 weaverryan

    Hey Enkhbilguun E.!

    Ah yes, great question! When we run the built-in web server, when you go to http://localhost:8000/genus/octopus/notes, it automatically knows to use app_dev.php. So, that's why it works in the tutorial :).

    But, the *real* solution is to basically do what you did - send the request to /app_dev.php/genus/octopus/notes. Of course, you don't want to hardcode this (then it would break on production!). What I would actually do is either:

    A) Use FOSJsRoutingBundle - which allows you to generate URLs from routes right inside your JS code. It's awesome!

    B) Generate the URL in Twig, set it on some global JS variable - e.g. window.notesUrl = '{{ path('...') }}'; - and access that inside of the React.js app.

    I didn't want to dive into these details this early in the Symfony series - but it's a really valid question.

    Cheers!

  • 2016-06-30 Enkhbilguun E.

    Hi Ryan,

    Thanks for the great tutorial. Can you tell me how I can set the Symfony that I am working on Development Environment?

    Unless I add /app_dev.php/ in the notes.react.js as below, it doesn't find http://domain/genus/octopus/notes.

    Thanks.

  • 2016-06-24 Victor Bocharsky

    Hey, congrats! Good work!

  • 2016-06-24 rddro

    Hey mate thank you :D Looking forward to it seems like a VERY powerful tool for managing all assets

    Got the pagination working also by transforming all the ES 6,7 stuff to ES5 and replacing the export calls
    export class App extends Component {
    constructor(props) {
    super(props);
    this.state = {
    data: [],
    offset: 0
    }
    }
    with creating a new react class like

    var App = React.createClass({
    getInitialState: function(props) {
    return {data: [],offset: 0};
    },

  • 2016-06-24 Victor Bocharsky

    Hey, @rddro !

    We do have Gulp course on KnpU, check it here.
    Yes, we plan to add "Webpack" course in the future, but I can't give you any estimates, it's only plans for now. What about browserify or other similar stuff... well, I think Webpack will be the first anyways :)

    Cheers!

  • 2016-06-24 rddro

    Hello , thanks it's working okish and updating info ^_^
    http://b5419ce9.ngrok.io/o-via...
    not too sure about the resource impact of this solution.
    <long post="" ahead=""> ->>>>>
    Have another issue do you know if there is a course on knpu that deals with implementing webpack ? Or can gulp ?? or browserify or the other millions things ?? that do the same thing as webpack. Never used these technologies before and this javascript world can get quite confusing.

    Basically what I'm trying to do now , is have symfony serve info through an API http://b5419ce9.ngrok.io/api/l...

    And on the front-end I want to render this as a react component like I did for the single product page http://b5419ce9.ngrok.io . The problem I'm having is with pagination <_< I'm trying to integrate this component

    https://github.com/AdeleD/reac... but can't figure out some things. Tried their demo , and was working ok. But not sure about the way the asset pipeline is setup.

    To my understanding there's no way to run ES6 and ES7 and import x from y or require() stuff in the browser that's why the need for a "transpiler" ?? like the babel thingie we used in this tutorial that translates ES6 and ES7 directives in browser readable code.

    The demo of this component uses webpack it seems to generate and hot reload changes to assets it seems.

    Using the browser babel core min.js , I tried to implement this for my product page by copying the react-paginate.js generated in the build folder and copying it to my assets and including it in a script tag but produces an error it doesn't like the fat arrow function handlePageClick. Also tried babel 5 and 6 but no go , even they said it's deprecated and recommend us to use server side transpiling.

    So I'm thinking of going for the same route and implement web-pack in my symfony project but not sure how to go about it couldn't find an example on how to include npm modules for use in the browser with symfony.

  • 2016-06-21 Robert

    Thank you Ryan,

    You are doing a very good job, probably one of the very few that uses psychology & words combined with enthusiasm to encourage people to build real applications in order to ultimately build confidence in development of non-trivially complex technologies.

    I have managed to figure this out. Simply by running apache web server instead of the inbuilt server.

  • 2016-06-21 Victor Bocharsky

    Hey, @rddro !

    Congrats! It looks pretty good. Don't forget to remove setInterval(this.loadNotesFromServer, 2000); from the componentDidMount(), your solution should work without it.

  • 2016-06-21 rddro

    Hello Ryan o/ Think I figured it out. The context was changed obviously >.<

    loadNotesFromServer: function() {
    var self = this;
    var socket = io.connect('http://localhost:4321');
    socket.on('message', function(message) {
    //some checks here on message ~
    $.ajax({
    url: self.props.url,
    success: function (data) {
    self.setState({notes: data.notes});
    }
    });
    });

    $.ajax({
    url: this.props.url,
    success: function (data) {
    this.setState({notes: data.notes});
    }.bind(this)
    });
    },

  • 2016-06-21 rddro

    Hello . I'm trying to implement this but I didn't go with the pusher seems a bit overkill and the commercial limitations are pretty strict so just tried a very very basic simple implementation with socket.io where i'm emitting a simple message changed when something changes.
    var socket = io.connect('http://localhost:4321');

    socket.on('message', function(message) {

    if(message=="changed")
    {
    }

    });

    The problem I'm having is I don't know how to re-render the component ? I tried in componentDidMount to call this.loadNotesFromServer without success . I'm thinking there's a way to do it via event emitter involved.

    Found this http://mwdesilva.com/posts/eve... will try to modify it for my case, hopefully can figure something out.

  • 2016-06-14 weaverryan

    Hi Robert!

    Thanks for the info! I don't *quite* understand what is and isn't working - so thanks in advance for your patience as I ask more question :)

    1) You mentioned {{ asset('image/picture.jpeg') }}. If you put this (<img src="{{ asset('image/picture.jpeg') }}"/> in your Twig template (no React, no JS), and obviously point it to a real file in your web/ directory, does the image show up?

    2) You mentioned you added the whatever.js script tag, which was a cool idea. You said that it does *not* alert. But then you said "If i include the scripts in the twig template file, it all runs smoothly together with react". Can you clarify a bit here? Under what circumstances do you include whatever.js and it does not work (e.g. did you add the script tag to the Twig template and it does not alert?) and under what circumstances *do* things work.

    Sorry for all the questions - for whatever reason, I haven't quite nailed down in my mind what is and isn't working :).

    Cheers!

  • 2016-06-12 Robert

    Hi Ryan,

    I am running the inbuilt server just as its described in the tutorial. The assets are located in the web directory, therefore I should be able to load them via {{ asset(image/picture.jpeg) }}. The problem is that it does link it, even if I were to access simply a favicon located in web directory.

    I have created JS file to test it, and used absolute paths too: <script src="{{ absolute_url(asset('js/whatever.js')) }}"></script>

    The firebug shows that it's all good:

    Host: localhost:9000
    Connection: close
    Content-Type: text/javascript; charset=UTF-8
    Content-Length: 22

    alert("Some text.");

    But there is no alert popping up nor images. If I include the scripts in the twig template file it all runs smoothly together with the react. What could be the problem?

  • 2016-06-10 weaverryan

    Hey Robert!

    Does the genus image (the octopus) load? Or do only the avatar images in the comments not load? Also, do you have the site installed in a sub-directory of some local domain (e.g. http://example.local/symfony)? The images are being loaded by just returning the path /images/ryan.jpeg - which works great, unless you have things in a subdirectory (i.e. because then it would need to be something like /symfony/images/ryan.jpg).

    But overall, the images are just static - so check out the path that's being rendered and compare it with the actual files that you have in your project.

    Let me know what you find out!

  • 2016-06-10 Robert

    Hi Ryan,

    Could you provide me explanation to why pictures may not be loading? CSS loads properly. I have cleared the cache via php bin/console cache:clear. Also JavaScript does not want to seem to load any of the react functionalities.

    Even though I have copied and pasted the code from the tutorial description both for the show template and changed ajax request. What could be the problem?

    Thank you

  • 2016-05-22 weaverryan

    Hi Alice!

    This is actually expected. The JavaScript makes an AJAX request every 2 seconds to check for new comments ( https://github.com/knpuniversi... ). This is called "polling" - it's a "cheap" way to get the "instant update" whenever someone makes a comment. In reality, if I want this type of functionality, I will usually use something like Pusher ( https://github.com/laupiFrpar/... ) to notify me instantly of when the changes happen. I would do this instead of making AJAX requests every XX seconds. But, you *are* seeing the expected behavior :).

    Cheers!

  • 2016-05-22 alice

    Thank you for your tutorials.
    I have a probleme in the last step (ReactJS talks to your API). I have creat the Json data and I can show it in my page but it never stop to do the Ajax request. Why ?

    https://drive.google.com/file/...

  • 2016-05-03 weaverryan

    Yes! That bundle is awesome!

  • 2016-05-03 Ленур

    For ajax urls I use https://github.com/FriendsOfSy... - this is very flexible :)

  • 2016-04-13 weaverryan

    Hi Michael!

    As you listed here (good details!), the problem is happening earlier - when the React app is being initialized. I think it's a small syntax issue on line 5. Try this:


    <notesection url="{notesUrl}"/>,

    The NoteSection upper-casing is important, but the real problem is that you have an extra set of quotes around {notesUrl} and the ending / is *inside* of these quotes (that last detail I believe is causing the error).

    Let me know if this helps!

    Cheers!

  • 2016-04-13 weaverryan

    Thanks for saying - cheers and keep up the good work :)

  • 2016-04-09 Michael

    I am not able to load the comments dynamically, even after replacing my base.html.twig, show.html.twig, GenusController.php,notes.react.js and main.js with the files in your finished folder? Where should I look for the mistake?

    There is one error I do have in the console:
    Uncaught SyntaxError: embedded: Unexpected token (6:59)

    4 | ReactDOM.render(

    5 | <notesection url="{notesUrl}/">,

    > 6 | document.getElementById('js-notes-wrapper');

    | ^

    7 | );

    Also if I look at genus/octopus/notes page, every forward slash is escaped by a blackslash. I don't think that should cause any issues though.

  • 2016-04-06 Agastya F. Alfath

    I've been enjoying your tutorials! Thank you!

  • 2016-03-19 richy

    Your tutorials are awesome and so well explained. Thank you and go on!!!

  • 2016-01-16 Matt W.

    I did copy your code over from the finish directory. Everything works perfectly now. I'm unable to find what the difference was. Thank you for your great videos and your response.

  • 2016-01-16 weaverryan

    Hey Matt!

    Hmm, it *is* possible that this is caused by an AJAX error from the /genus/octopus/notes endpoint. I would first debug the response that you're getting back after making the AJAX call - in the success function of notes.react.js around line 17 (success:function ()...). If the response did not contain the valid JSON (e.g. JSON with a notes key), then this would ultimately cause this.props.notes to be undefined. But, it could be something else too :). If you download the course code for this tutorial and use the "finish" directory - you could double-check and see if that works, then compare it to your code.

    Let me know how it goes!

  • 2016-01-16 Matt W.

    Firefox is giving me the error "TypeError: this.props.notes is undefined". I am not familiar with react. Do you have any suggestions?

    Thank you.