Scroll down to the script below, click on any sentence (including terminal blocks!) to jump to that spot in the video!Cool, got it! Show me the script!
This Chapter isn't quite ready yet
Rest assured, the gnomes are hard at work on completing this video
We now GET and DELETE the rep logs via the API. The last task is to create
them when the form submits. Look back at
RepLogController: we can POST
/reps to create a new rep log. I want to show you just a little bit
about how this works.
The endpoint expects the data to be sent as JSON. See: the first thing we do is
json_decode the request content. Then, we use Symfony's form system: we have a
RepLogType with two fields:
item. This is bound directly
RepLog entity class, not the model class.
Using the form system is optional. You could also just use the raw data to manually
populate a new
RepLog entity object. You could also use the serializer to
deserialize the data to a
These are all great options, and whatever you choose, you'll ultimately have a
RepLog entity object populated with data. I attach this to our user, then flush
it to the database.
For the response, we always serialize
RepLogApiModel objects. So, after saving,
we convert the
RepLog into a
RepLogApiModel, turn that into JSON and return
I also have some data validation above, which we'll handle in React later.
To make the API request in React, start, as we always do, in
Create a third function:
export function createRepLog. This needs a
argument, which will be an object that has all the fields that should be sent to
Use the new
fetchJson() function to
/reps with a
method set to
time, we also need to set the
body of the request: use
Set one more option: a
headers key with
Content-Type set to
This is optional: my API doesn't actually read or care about this. But, because
we are sending JSON, it's a best-practice to say this. And, later, our API
will start requiring this.
Ok, API function done! Head back to
RepLogApp and scroll up: import
Then, down in
handleAddRepLog, use it!
createRepLog(newRep). To see what
we get back, add
Well... let's see what happens! Move over and refresh. Okay, select "Big Fat Cat", 10 times and... submit! Boo! The POST failed! A 400 error!
Go check it out. Interesting... we get an error that this form should not contain
extra fields. Something is not right. In Symfony, you can look at the profiler
for any AJAX request. Click into this one and go to the "Forms" tab. Ah, the error
is attached to the top of the form, not a specific field. Click
to get more details. Oh... this
value key holds the secret. Our React app is sending
totalWeightLifted to the API. But, look at the form! The only
item! We shouldn't be sending any of these other fields!
itemLabel is almost correct. It should be called
item. And instead
of being the text, the server wants the
value from the selected option - something
Ok, so we have some work to do. Head back to
RepLogApp. First: remove the stuff
we don't need: we don't need
id and we're not responsible for sending the
totalWeightLifted. Then, rename
item. Rename the argument
too, because this now needs to be the option value. This function is eventually
onAddRepLog. Instead of
newRep now contains the data our API needs! Woohoo! But...
interesting. It turns out that, at the moment the user submits the form, we don't
have all the data we need to update the state. In fact, we never did! We were just
faking it by using a random value for
This is a case where we can't perform an optimistic UI update: we can't update the state until we get more info back from the server. This is no big deal, it just requires a bit more work.
Comment out the
setState() call. Let's refresh and at least see if the API
call works. Lift my big fat cat 55 times and hit enter. Yes! No errors! The
console log is coming from the POST response... it looks perfect! Id 30, it returns
itemLabel and also calculates the
totalWeightLifted. Refresh, yep! There
is the new rep log!
Ok, let's update the state. Because our API rocks, we know that the
this.setState() but pass it a callback with
Once again, the new state depends on the existing state.
To add the new rep log without mutating the state, use
const newRepLogs = an
...prevState.repLogs, repLog. Return the new state:
Remove all the old code below.
Let's try it! Make sure the page is refreshed. Lift our normal cat this time, 10 times, and boom! We've got it!
This was the first time that our React app did not have all the data it needed to update state immediately. It needed to wait until the AJAX request finished.
Again, that's no huge deal... but it's a bit more work, and it will require you to add more "loading" screens so that it looks like your app is saving. It's just simpler if you can update the state immediately.
If you're creating a lot of resources, keep this in mind!