# Django React full CRUD We've already created a basic app and tested it via the DRF postman to make sure everything is working. Now let's implement some CRUD to it! This is going to require some refactoring. We will call this new component `AddTodo.jsx`. However, don't let that fool you. All functionality will now occur here, as we will be wanting our map of `todoList` inside `AddTodo.jsx` to properly target a todo list item for CRUD. Before we do any of that though, let's actually learn a bit more about axios. Up until now, we've mostly been using `axios.get` to grab from APIs and whatnot. The reality is that this is but a mere fraction of the power of Axios. Axios actually comes fully stocked with built-in methods for all CRUD functionality, not just `get`. What is happening behind the scenes when we import axios and then call `axios.get` is we create what is called an Axios Instance which is configured for getting. It looks a bit like this: ```javascript! axios({ method: 'get', url: 'http://bit.ly/2mTM3nY', responseType: 'stream' }) .then(function (response) { response.data.pipe(fs.createWriteStream('ada_lovelace.jpg')) }); ``` But for ease of use, they allow us to just say `axios.get`. It's similar to when we create a react app using `npx create-react-app`, we are creating an INSTANCE of a react app, complete with the immense amount of dependencies and functionality that comes bundled with it. However, we can do more than just create our Axios Instance behind the scenes. We can very deliberately create it, configure it, and then use it all across our app in a very slick and react-y manner. So let's set up an Axios instance that will call our backend for us, and allow for full CRUD from inside our react app. Touch a file called `API.js`. ```javascript // inside API.js import axios from 'axios' export default axios.create({ baseURL: "/api/todos", headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' } }) ``` So what's going on here? We import axios like normal, but instead of using just one of the built in methods, we use `axios.create` to create an instance of Axios. You can learn more about the nature and power of the Axios instance in the axios docs [here](https://axios-http.com/docs/instance) (it's even conveniently called 'The Axios Instance'). For the purpose of this lesson, just know that these few lines of code have provided us with all we need to perform full crud. We set the baseURL to the same route that we confirmed with DRF to be where our todos live, and then set our headers to accept json, as that's of course the content type we'll be wanting from our API. Now that we have that done, let's set up the boilerplate of `AddTodo`. ```javascript import { useState, useEffect } from 'react' import API from './API' export default function AddTodo(props) { const [title, setTitle] = useState('') const [description, setDescription] = useState('') const [completed, setCompleted] = useState(false) const [todoList, setTodoList] = useState(props.todoList) } ``` Notice we have props here. I've chose to keep the original axios call to the backend inside of `App`, set the state of `todoList` there, and then pass it down as props to `AddTodo`. You can move all that code inside `AddTodo` if you feel like it. Here's where things get REALLY cool. Let's set up what functionally become our controllers. ```javascript! // inside AddTodo ... useEffect(() => { refreshTodos() }, []) const refreshTodos = () => { API.get("/") .then((res) => { setTodoList(res.data) }) .catch(console.error) } const onSubmit = (e) => { e.preventDefault() let todo = { title, description, completed } API.post("/", todo).then(() => refreshTodos()) } const onUpdate = (id) => { let todo = {title, description, completed} API.patch(`/${id}/`, todo).then((res) => refreshTodos()) } const onDelete = (id) => { API.delete(`/${id}/`).then((res) => refreshTodos()) } const selectTodo = (id) => { let todo = todoList.filter((todo) => todo.id === id)[0] setTitle(todo.title) setDescription(todo.description) setCompleted(todo.completed) } ``` Let's break down what's happening here, because in these 40 lines of code is everything we need for CRUD on our little todo app. First we set up an initial refresh of `todoList` that runs once on `componentDidMount` via a `useEffect` with an empty dependency array. next we define a generic `get` method that gets all todos. We'll be using this to get our new list of update todos everytime CRUD occurs. Notice how all of these controllers call `API.something`. This is our axios instance, which, again, comes bundled with all the HTTP verbs we are familiar with. All we needed to do was create it, import it, and now all those methods are available to us anywhere in our app (told you it was slick). We've got a submit function to handle form submission. As you can clearly see, it posts to our database thanks to axios. We instantiate a new todo with the properties we defined in our model (these are the values they're looking for. Go ahead and try and change them to something else, you'll get a 400 request), and then we just call `API.post` while passing in our new todo item, then call our get method of `refreshTodos`. Same thing with updating. We pass in our values (feel free to play around with this. For example, if you exclude a property from the curlies, it will not be updated), call a `.patch` method from our Axios instance, and then `refreshTodos`. Finally we have deleting/destroying. I think you get the idea by now. Call our axios instance, tell it to delete, pass it the id of the thing being deleted, `refreshTodos`. Now what is up with this `selectTodo` method? Well I decided to try something interesting for you all. Before in class, if you recall, we struggled greatly with setting state of an array when you're trying to just target one thing and replace it in its current location in the array. This can be done by finding its index in the array and splicing it, and that is most likely the more elegant way. But I find this way to be rather fascinating, and with some cleanup, I feel it could be a very fun way to handle updating in particular. We'll touch on this more when we actually have stuff on the screen. Let's do that now! ```javascript // inside AddTodo.js ... return( <> <div> {todoList.map((e) => { return( <div style={{color: e.completed ? 'green' : 'red', borderRadius: '1px'}} key={e.id}> <h2> {e.title} </h2> <p> {e.description} </p> <button onClick={() => onDelete(e.id)}> Delete </button> <button onClick={() => selectTodo(e.id)}> Select </button> <button onClick={() => setCompleted(true)}> Completed! </button> <button onClick={() => setCompleted(false)}> Not Completed! </button> <button onClick={() => onUpdate(e.id)}> Edit </button> </div> ) })} </div> <h1> Add/Edit a task! </h1> <form> <input value={title} onChange={e=> setTitle(e.target.value)} placeholder={'title'} type='text' name='title' /> <input value={description} onChange={e=> setDescription(e.target.value)} placeholder={'description'} type='text' name='description' /> </form> <button onClick={onSubmit}> Add </ button> </> ) ``` Let's break it down again. First is the copypasta of the map from `App`, with the addition of buttons to handle our CRUD functionality. Next is the form. 2 inputs, one for `title` and one for `description`. Here is where we put our submit button which calls our `onSubmit` function, AKA the `post` method of our axios instance. Here where the code gets admittedly quite inelegant, due to my decision to try to code around needing to splice the state of `todoList`. When you hit the `Select` button contained in each todo item, it filters for that specific todo item, targets the form due to their values being tied to the values of our `title` and `description` states, and then when we hit the edit button (yes, inside of each todo item, I know, I know...), ONLY because we've selected it first, it will send a `.patch` request to the todo item at that specific id, allowing for editing in place without splicing. Same thing with the completed property, which is also quite inelegant in its current form. As you can see from the code, what's actually happening is when you click the `Completed!` button, it sets the state of completed to true, which then gets passed in alongside `title` and `description` when we run our `.patch`. But realistically the state of `completed` is now just permanently true. Hence a `not completed` button. Oddly enough, trying to set the state of `completed` back to false in the `onSubmit` didn't work. That of course would have made it slightly nicer of a UX but alas. All this being said, the aesthetics and UX of the app is now terrible, but functionality is there. I know everyone here is a huge fan of react, so let's think of some ways to improve it together! The fun of this tech stack, as I hope you're noticing is how diverse you can get with how you achieve your functionality. So for those of you interested in utilizing this, lets get to thinking!