Getting our list of Todos from the server

To get Todos, we'll need to change how our state is built out. If you think back to our earliest implementations of the TodoList component, we built all of our Todos as an array of strings and then allowed our Todo component to do the rest of the work. This ends up not being a great model when we’re actually getting information in and out of our server, so we’ll want to transition ourselves over from relying on simple strings to store the information about the Todos to a model where the data structures for the Todos match both their component implementations and their data representations on the server side.

To start modifying TodoList to fit our new world, we'll want to start with a blank list of Todos and a flag to capture whether the data has been loaded yet or not. In src/TodoList/TodoList.js add the following code:

  constructor(props) {
super(props);

this.state = {
items: [],
loaded: false
};

this.addTodo = this.addTodo.bind(this);
this.removeTodo = this.removeTodo.bind(this);
}

This loaded flag is actually pretty important; without it, we run into a scenario where when the page first loads, either the page looks blank or it displays No items, when in reality it just hasn’t loaded the full list of items yet! To create a better user experience, we’ll instead want to rely on a flag that tells the application whether it has completed loading and displays a message about that to the user, instead of relying on whether the items state property has values in it.

If you remember from our server, Todo items will now be populated from the data structure that we created in our server file, so they can no longer just be the descriptions. This will require us to restructure some of our code, so we'll go back through and fix up the code that is broken by this change. First, let's add a new item:

  addTodo(description) {
const newItem = {
description: description,
done: false,
critical: false
};
this.setState({
items: [...this.state.items, newItem]
});
}

It’s easier for us to break newItem into a separate variable and then pass that into the setState() call, otherwise we’d end up making that line of code really long and also very fragile in regards to any data-structure changes that might happen along the way:

  removeTodo(removeItem) {
const filteredItems = this.state.items.filter(todo => {
return todo.description !== removeItem;
});
this.setState({ items: filteredItems });
}

We also do a similar operation with our removeTodo call. We’ll move our list of filtered items, based on the description. Next, is our renderItems() call, which is also going to check the new state variable to see whether the data has been loaded from the server yet. Also, we’re going to pass in a few new properties to our Todo component to make it respect our data structure. Specifically, we’ll pass in the id, done, and critical flags to allow those to be set in Todo as part of the passed-in props:

  renderItems() {
if (this.state.loaded) {
return this.state.items.map(todo => (
<Fragment key={'item-' + todo.description}>
<Todo
id={todo.id}
key={todo.id}
description={todo.description}
removeTodo={this.removeTodo}
done={todo.done}
critical={todo.critical}
/>
<Divider key={'divide-' + todo.description} />
</Fragment>
));
} else {
return <p>Still Loading...</p>;
}
}

Note that we're passing in some new props to the Todo components, which means we'll need to modify those to allow state to be set via props for whether a Todo is done and whether a Todo is critical. Open up src/Todo/Todo.js and we'll take care of that really quickly in the constructor() function:

  constructor(props) {
super(props);
this.state = {
done: props.done,
critical: props.critical
};

this.markAsDone = this.markAsDone.bind(this);
this.removeTodo = this.removeTodo.bind(this);
this.markCritical = this.markCritical.bind(this);
}

Head back to src/TodoList/TodoList.js, and let's start writing our Async/Await functionality. We'll create a new function that is part of the React standard component life cycle, componentDidMount(), where we will declare it as an async function. Remember that any place we want to use await in our code, we have to do so inside of a function that has been declared as async! We'll start off with a simple body so that we can verify how it all works first, and then we'll flesh it out a little more:

  async componentDidMount() {
this.setState({ loaded: true });
}

Next, we'll need to use fetch to make the request to our simulated backend, where we will await the results of fetch:

const res = await fetch('/api/todos', { accept: 'application/json' });
Remember that we are proxying requests to a different backend through Create React App! As a result, we don't need to specify a port or host, since it is pretending to be the same port/host.
This backend server is meant to act as a placeholder for when you build a backend onto the same application or service as where this code runs for minimum latency. This is a great model for when you're building the frontend for something but the backend isn't fully built yet!

We'll also need to take those results and convert them into JSON if we want to do anything with them, which is also an async call:

const json = await res.json();

Finally, don't forget that our server returns data back in the following form:

{
todos: [ ...todo1, ...todo2, ...etc ]
}

So finally, we need to replace the state of items to the new state:

this.setState({ items: json.todos, loaded: true });

And there we are! Now when the page refreshes, you should see the same list of components as before but now the data comes from our simulated backend instead! This should leave the full body of this function looking like the following code snippet:

async componentDidMount() {
const res = await fetch('/api/todos', { accept: 'application/json' });
const json = await res.json();
this.setState({ items: json.todos, loaded: true });
}

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.140.198.173