One place for hosting & domains

      22 Best Visual Studio Code Extensions for Web Development

      Debugger for Chrome

      Believe it or not, debugging JavaScript means more than just writing console.log() statements (although that’s a lot of it). Chrome has features built in that make debugging a much better experience. This extension gives you all (or close to all) of those debugging features right inside of VS Code!

      If you want to learn more about debugging you should read Debugging JavaScript in Chrome and Visual Studio Code.

      Marketplace Link: Debugger for Chrome

      JavaScript Snippets

      I loooove snippet extensions. I’m a firm believer that there’s no need to retype the same piece of code over and over again. This extensions provides you with snippets for popular pieces of modern (ES6) JavaScript code.

      Side note…if you’re not using ES6 JavaScript features, you should be!

      Marketplace Link: JavaScript Snippets

      ESLint

      Want to write better code? Want consistent formatting across your team? Install ESLint. This extension can be configured to auto format your code as well as “yell” with linting errors/warnings. VS Code specifically is also perfectly configured to show you these errors/warnings.

      Check out the ESLint docs for more info.

      Marketplace Link: ESLint

      Live Server

      Make changes in code editor, switch to browser, and refresh to see changes. That’s the endless cycle of a developer, but what if your browser would automatically refresh anytime you make changes? That’s where Live Server comes in!

      It also runs your app on a localhost server. There are some things you can only test when running your app from a server, so this is a nice benefit.

      Marketplace Link: Live Server

      Bracket Pair Colorizer

      Brackets are the bane of a developer’s existence. With tons of nested code, it gets almost impossible to determine which brackets match up with each other. Bracket Pair Colorizer (as you might expect) colors matching brackets to make your code much more readable. Trust me, you want this!

      Marketplace Link: Bracket Pair Colorizer

      Auto Rename Tag

      Need to rename an element in HTML? Well, with Auto Rename Tag, you just need to rename either the opening or closing tag, and the other will be renamed automatically. Simple, but effective!

      Marketplace Link: Auto Rename Tag

      Quokka

      Need a quick place to test out some JavaScript? I used to open up the console in Chrome and type some code right there, but there were many downsides. Quokka gives you a JavaScript (and TypeScript) scratchpad in VS Code. This means you can test out a piece of code right there in your favorite editor!

      Marketplace Link: Quokka

      Path Intellisense

      In large projects, remembering specific file names and the directories your files are in can get tricky. This extension will provide you intellisense for just that. As you start typing a path in quotations, you will get intellisense for directories and file names. This will save you from spending a lot of time in the file explorer.

      Marketplace Link: Path Intellisense

      Project Manager

      One thing I hate is switching between projects in VS Code. Every time I have to open the file explorer and find the project on my computer. But that changes with Project Manager. With this extension, you get an extra menu in your side menu for your projects. You can quickly switch between projects, save favorites, or auto-detect projects Git projects from your file system.

      If you work on multiple different projects, this is a great way to stay organized and be more efficient.

      Marketplace Link: Project Manager

      Editor Config

      Editor Config is a standard of a handlful of coding styles that are respected across major text editors/IDEs. Here’s how it works. You save a config file in your repository which your editor respects. In this case, you have to add an extension to VS Code for it to respect these config files. Super easy to setup and works great on team projects.

      Read more on the Editor Config Docs.

      Marketplace Link: Editor Config

      Sublime Keybindings

      Are you an avid Sublime user, nervous to switch over to VS Code? This extension will make you feel right at home, by changing all of the shortcuts to match those of Sublime. Now, what excuse do you have for not switching over?

      Marketplace Link: Sublime Keybindings

      Browser Preview

      I love the Live Server extension (mentioned above), but his extension goes another step further in terms of convenience. It gives you a live-reloading preview right inside of VS Code. No more having to tab over to your browser to see a small change!

      Marketplace Link: Browser Preview

      Git Lens

      There a bunch of git extensions out there, but one is the most powerful with tons of features. You get blame information, line and file history, commit searching, and so much more. If you need help with your Git workflow, start with this extension!

      Marketplace Link: **Git Lens

      You know those fancy code screenshots you see in articles and tweets? Well, most likely they came from Polacode. It’s super simple to use. Copy a piece of code to your clipboard, open up the extension, paste the code, and click to save your image!

      Marketplace Link: Polacode

      Prettier

      DONT spend time formatting your code…just DONT. There’s no need to. Ealier, I mentioned ESLint which provides formatting and linting. If you don’t need the linting part, then go with Prettier. It’s super easy to setup and can be configured to formatted your code automatically on save.

      Never worry about formatting again!

      Marketplace Link: Prettier

      Better Comments

      This extension color codes various types of comments to give them different significance and stand out from the rest of your code. I use this ALL THE TIME for todo comments. It’s hard to ignore a big orange comment telling me I’ve got some unfinished work to do.

      There are also color codes for questions, alerts, and highlights. You can also add your own!

      Marketplace Link: Better Comments

      Git Link

      If you’ve ever wanted to view a file that you’re working on in Github, this extension is for you. After installing, just right-click in your file and you’ll see the option to open it in Github. This is great for checking history, branch versions, etc. if you’re not using the Git Lens extension.

      Marketplace Link: Git Link

      VS Code Icons

      Did you know you can customize the icons in VS Code? If you look in settings, you’ll seen an option for “File Icon Theme”. From there you can choose from the pre-installed icons or install an icon pack. This extension gives you a pretty sweet icon pack that is used by over 11 million people!

      Marketplace Link: VS Code Icons

      Material Icon Theme

      Fan of Google’s Material design? Then, check out this Material themed icon pack. There’s hundreds of different icons and they are pretty awesome looking!

      Marketplace Link: Material Icon Theme

      Settings Sync

      Developers, myself included, spend a lot of time customizing their dev environment, especially their text editors. With the Settings Sync extension, you can save your setting off in Github. Then, you can load them to any new version of VS Code with one command. Don’t get caught without your amazing setup ever again!

      Marketplace Link: Settings Sync

      Better Align

      If you’re the kind of person who loves perfect alignment in your code, you need to get Better Align. You can align multiple variable declarations, trailing comments, sections of code, etc. There’s no better way to get a feel for how amazing this extension is than installing it and giving it a try!

      Marketplace Link: Better Align

      VIM keybindings](https://marketplace.visualstudio.com/items?itemName=vscodevim.vim)

      Are you a VIM power user? Bless you if you are, but you can take all of that VIM power user knowledge and use it right inside VS Code. Not the path I personally want to go, but I know how insane productivity can be when using VIM to its potential, so more power to you.

      Marketplace Link: VIM Keybindings

      What are your favorite VS Code Extensions for web development? Let us know in the comments.

      Understanding and Working with Files in Laravel

      Introduction

      File uploads are one the most commonly used features on the web. From uploading avatars to family pictures to sending documents via email, we can’t do without files on the web.

      In today’s article will cover all the ways to handle files in Laravel. After reading the article, If we left something out please let us know in the comments and we’ll update the post accordingly.

      Handling files is another thing Laravel has simplified in its ecosystem. Before we get started, we’ll need a few things. First, a Laravel project. There are a few ways to create a new Laravel project, but let’s stick to composer for now.

      1. composer create-project --prefer-dist laravel/laravel files

      Where files is the name of our project. After installing the app, we’ll need a few packages installed, so, let’s get them out of the way. You should note that these packages are only necessary if you intend to save images to Amazon’s s3 or manipulate images like cropping, filters, etc.

      1. composer require league/flysystem-aws-s3-v3:~1.0 intervention/image:~2.4

      After installing the dependencies, the final one is Mailtrap. Mailtrap is a fake SMTP server for development teams to test, view, and share emails sent from the development and staging environments without spamming real customers. So head over to Mailtrap and create a new inbox for testing.

      Then, in welcome.blade.php update the head tag to:

      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <title>File uploads</title>
      <style>
        * {
          font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
              "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji",
              "Segoe UI Emoji", "Segoe UI Symbol";
        }
      </style>
      

      Modify the body contents to:

      <form action="/process" enctype="multipart/form-data" method="POST">
          <p>
              <label for="photo">
                  <input type="file" name="photo" id="photo">
              </label>
          </p>
          <button>Upload</button>
          {{ csrf_field() }}
      </form>
      

      For the file upload form, the enctype="multipart/form-data" and method="POST" are extremely important as the browser will know how to properly format the request. {{ csrf_field() }} is Laravel specific and will generate a hidden input field with a token that Laravel can use to verify the form submission is legit.

      If the CSRF token does not exist on the page, Laravel will show “The page has expired due to inactivity” page.

      Now that we have our dependencies out of the way, let’s get started.

      Development, as we know it in 2018, is growing fast, and in most cases, there are many solutions to one problem. Take file hosting, for example, now we have so many options to store files, the sheer number of solutions ranging from self-hosted to FTP to cloud storage to GFS and many others.

      Since Laravel is framework that encourages flexibility, it has a native way to handle the many file structures. Be it local, Amazon’s s3, Google’s Cloud, Laravel has you covered.

      Laravel’s solution to this problem is to call them disks. Makes sense, any file storage system you can think of can be labeled as a disk in Laravel. In this regard, Laravel comes with native support for some providers (disks). We have local, public, s3, Rackspace, FTP, etc. All this is possible because of Flysystem.

      If you open config/filesystems.php you’ll see the available disks and their respected configuration.

      From the introduction section above, we have a form with a file input ready to be processed. We can see that the form is pointed to /process. In routes/web.php, we define a new POST /process route.

      use Illuminate\Http\Request;
      
      Route::post('process', function (Request $request) {
          $path = $request->file('photo')->store('photos');
      
          dd($path);
      });
      

      What the above code does is grab the photo field from the request and save it to the photos folder. dd() is a Laravel function that kills the running script and dumps the argument to the page. For me, the file was saved to photos/3hcX8yrOs2NYhpadt4Eacq4TFtpVYUCw6VTRJhfn.png. To find this file on the file system, navigate to storage/app and you’ll find the uploaded file.

      If you don’t like the default naming pattern provided by Laravel, you can provide yours using the storeAs method.

      Route::post('process', function (Request $request) {
          
          $file = $request->file('photo');
          
          
          $filename = 'profile-photo-' . time() . '.' . $file->getClientOriginalExtension();
          
          
          $path = $file->storeAs('photos', $filename);
          
          dd($path);
      });
      

      After running the above code, I got photos/profile-photo-1517311378.png.

      In config/filesystems.php you can see the disks local and public defined. By default, Laravel uses the local disk configuration. The major difference between local and the public disk is that local is private and cannot be accessed from the browser while public can be accessed from the browser.

      Since the public disk is in storage/app/public and Laravel’s server root is in public you need to link storage/app/public to Laravel’s public folder. We can do that with our trusty artisan by running php artisan storage:link.

      Since Laravel doesn’t provide a function to upload multiple files, we need to do that ourselves. It’s not much different from what we’ve been doing so far, we just need a loop.

      First, let’s update our file upload input to accept multiple files.

      <input type="file" name="photos[]" id="photo" multiple>
      

      When we try to process this $request->file(‘photos’), it’s now an array of UploadedFile instances so we need to loop through the array and save each file.

      Route::post('process', function (Request $request) {
          $photos = $request->file('photos');
          $paths  = [];
      
          foreach ($photos as $photo) {
              $extension = $photo->getClientOriginalExtension();
              $filename  = 'profile-photo-' . time() . '.' . $extension;
              $paths[]   = $photo->storeAs('photos', $filename);
          }
      
          dd($paths);
      });
      

      After running this, I got the following array, since I uploaded a GIF and a PNG:

      array:2 [0 => "photos/profile-photo-1517315875.gif"
        1 => "photos/profile-photo-1517315875.png"
      ]
      

      Validation for file uploads is extremely important. Apart from preventing users from uploading the wrong file types, it’s also for security. Let me give an example regarding security. There’s a PHP configuration option cgi.fix_pathinfo=1. What this does is when it encounters a file like https://example.com/images/evil.jpg/nonexistent.php, PHP will assume nonexistent.php is a PHP file and it will try to run it. When it discovers that nonexistent.php doesn’t exist, PHP will be like “I need to fix this ASAP” and try to execute evil.jpg (a PHP file disguised as a JPEG). Because evil.jpg wasn’t validated when it was uploaded, a hacker now has a script they can freely run live on your server… Not… good.

      To validate files in Laravel, there are so many ways, but let’s stick to controller validation.

      Route::post('process', function (Request $request) {
          
          $validation = $request->validate([
              'photo' => 'required|file|image|mimes:jpeg,png,gif,webp|max:2048'
              
              
          ]);
          $file      = $validation['photo']; 
          $extension = $file->getClientOriginalExtension();
          $filename  = 'profile-photo-' . time() . '.' . $extension;
          $path      = $file->storeAs('photos', $filename);
      
          dd($path);
      });
      

      For the above snippet, we told Laravel to make sure the field with the name of the photo is required, a successfully uploaded file, it’s an image, it has one of the defined mime types, and it’s a max of 2048 kilobytes ~~ 2 megabytes.

      Now, when a malicious user uploads a disguised file, the file will fail validation and if for some weird reason you leave cgi.fix_pathinfo on, this is not a means by which you can get PWNED!!!

      If you head over to Laravel’s validation page you’ll see a whole bunch of validation rules.

      Okay, your site is now an adult, it has many visitors and you decide it’s time to move to the cloud. Or maybe from the beginning, you decided your files will live on a separate server. The good news is Laravel comes with support for many cloud providers, but, for this tutorial, let’s stick with Amazon.

      Earlier we installed league/flysystem-aws-s3-v3 through composer. Laravel will automatically look for it if you choose to use Amazon S3 or throw an exception.

      To upload files to the cloud, just use:

      $request->file('photo')->store('photos', 's3');
      

      For multiple file uploads:

      foreach ($photos as $photo) {
          $extension = $photo->getClientOriginalExtension();
          $filename  = 'profile-photo-' . time() . '.' . $extension;
          $paths[]   = $photo->storeAs('photos', $filename, 's3');
      }
      

      Users may have already uploaded files before you decide to switch to a cloud provider, you can check the upcoming sections for what to do when files already exist.

      Note: You’ll have to configure your Amazon S3 credentials in config/filesystems.php.

      Before we do this, let’s quickly configure our mail environment. In .env file you will see this section

      MAIL_DRIVER=smtp
      MAIL_HOST=smtp.mailtrap.io
      MAIL_PORT=2525
      MAIL_USERNAME=null
      MAIL_PASSWORD=null
      MAIL_ENCRYPTION=null
      

      We need a username and password which we can get at Mailtrap.io. Mailtrap is really good for testing emails during development as you don’t have to crowd your email with spam. You can also share inboxes with team members or create separate inboxes.

      First, create an account and login:

      1. Create a new inbox
      2. Click to open inbox
      3. Copy username and password under SMTP section

      After copying credentials, we can modify .env to:

      MAIL_DRIVER=smtp
      MAIL_HOST=smtp.mailtrap.io
      MAIL_PORT=2525
      MAIL_USERNAME=USERNAME
      MAIL_PASSWORD=PASSWORD
      MAIL_ENCRYPTION=null
      

      Don’t bother using mine, I deleted it.

      Create your mailable

      1. php artisan make:mail FileDownloaded

      Then, edit its build method and change it to:

      public function build()
      {
          return $this->from('[email protected]')
              ->view('emails.files_downloaded')
              ->attach(storage_path('app/file.txt'), [
                  'as' => 'secret.txt'
              ]);
      }
      

      As you can see from the method above, we pass the absolute file path to the attach() method and pass an optional array where we can change the name of the attachment or even add custom headers. Next, we need to create our email view.

      Create a new view file in resources/views/emails/files_downloaded.blade.php and place the content below.

      <h1>Only you can stop forest fires</h1>
      <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Labore at reiciendis consequatur, ea culpa molestiae ad minima est quibusdam ducimus laboriosam dolorem, quasi sequi! Atque dolore ullam nisi accusantium. Tenetur!</p>
      

      Now, in routes/web.php we can create a new route and trigger a mail when we visit it.

      use App\Mail\FileDownloaded;
      
      Route::get('mail', function () {
          $email = '[email protected]';
      
          Mail::to($email)->send(new FileDownloaded);
      
          dd('done');
      });
      

      If you head over to Mailtrap, you should see this.

      In an application, it’s not every time we process files through uploads. Sometimes, we decide to defer cloud file uploads till a certain user action is complete. Other times we have some files on disk before switching to a cloud provider. For times like this, Laravel provides a convenient Storage facade. For those who don’t know, facades in Laravel are class aliases. So instead of doing something like Symfony\File\Whatever\Long\Namespace\UploadedFile, we can do Storage instead.

      Choosing a disk to upload a file. If no disk is specified, Laravel looks in config/filesystems.php and uses the default disk.

      Storage::disk('local')->exists('file.txt');
      

      Use default cloud provider:

      
      Storage::cloud()->exists('file.txt');
      

      Create a new file with contents:

      Storage::put('file.txt', 'Contents');
      

      Prepend to file:

      Storage::prepend('file.txt', 'Prepended Text');
      

      Append to file:

      Storage::append('file.txt', 'Prepended Text');
      

      Get file contents:

      Storage::get('file.txt')
      

      Check if file exists:

      Storage::exists('file.txt')
      

      Force file download:

      Storage::download('file.txt', $name, $headers); 
      

      Generate publicly accessible URL:

      Storage::url('file.txt');
      

      Generate a temporary public URL (i.e., files that won’t exist after a set time). This will only work for cloud providers as Laravel doesn’t yet know how to handle the generation of temporary URLs for the local disk.

      Storage::temporaryUrl('file.txt’, now()->addMinutes(10));
      

      Get file size:

      Storage::size('file.txt');
      

      Last modified date:

      Storage::lastModified('file.txt')
      

      Copy files:

      Storage::copy('file.txt', 'shared/file.txt');
      

      Move files:

      Storage::move('file.txt', 'secret/file.txt');
      

      Delete files:

      Storage::delete('file.txt');
      

      To delete multiple files:

      Storage::delete(['file1.txt', 'file2.txt']);
      

      Resizing images, adding filters, etc. This is where Laravel needs external help. Adding this feature natively to Laravel will only bloat the application since no installs need it. We need a package called intervention/image. We already installed this package, but for reference.

      1. composer require intervention/image

      Since Laravel can automatically detect packages, we don’t need to register anything. If you are using a version of Laravel lesser than 5.5 read this.

      To resize an image

      $image = Image::make(storage_path('app/public/profile.jpg'))->resize(300, 200);
      

      Even Laravel’s packages are fluent.

      You can head over to their website and see all the fancy effects and filters you can add to your image.

      Laravel also provides handy helpers to work with directories. They are all based on PHP iterators so they’ll provide the utmost performance.

      To get all files:

      Storage::files
      

      To get all files in a directory including files in sub-folders

      Storage::allFiles($directory_name);
      

      To get all directories within a directory

      Storage::directories($directory_name);
      

      To get all directories within a directory including files in sub-directories

      Storage::allDirectories($directory_name);
      

      Make a directory

      Storage::makeDirectory($directory_name);
      

      Delete a directory

      Storage::deleteDirectory($directory_name);
      

      If we left anything out, please let us know down in the comments. Also, checkout Mailtrap, they are really good and it will help you sail through the development phase with regards to debugging emails.

      Create a Custom useFetch() React Hook

      Introduction

      A custom hook is a JavaScript function with a unique naming convention that requires –

      1. the function name to start with use and
      2. the function may call other Hooks

      The whole idea behind custom hooks is just so that we can extract component logic into reusable functions.

      Often times as we build out React applications, we see ourselves writing almost the same exact codes in two or more different components. Ideally what we could do in such cases would be to extract that recurrent logic into a reusable piece of code (hook) and reuse it where the need be.

      Before hooks, we share stateful logic between components using render props and higher-order components, however, since the introduction of hooks and since we came to understand how neat they make these concepts, it no longer made sense to keep using those. Basically, when we want to share logic between two JavaScript functions, we extract it to a third function possibly because both components and hooks are equally just functions.

      The rationale behind this move is not different from what we have already explained above. Compared to using the native fetch API out of the box, abstracting it into the useFetch hook gives us a one-liner ability, more declarative code style, reusable logic and an overall cleaner code as we’ll see in a minute. Consider this simple useFetch example:

      const useFetch = (url, options) => {
        const [response, setResponse] = React.useState(null);
        useEffect(async () => {
            const res = await fetch(url, options);
            const json = await res.json();
            setResponse(json);
        });
        return response;
      };
      

      Here, the effect hook called useEffect is used to perform major functions —

      1. fetch the data with the native fetch API and
      2. Set the data in the local state of the component with the state hook’s update function.

      Also, notice that the promise resolving happens with async/await.

      The effect hook runs on two occasions — When the component mounts and also when the component updates. What this means is, if nothing is done about the useFetch example above, we will most definitely run into a scary recurrent loop cycle. Why? Because we are setting the state after every data fetch, as a result, when we set the state, the component updates and the effect runs again.

      Obviously, this will result in an infinite data fetching loop and we don’t want that. What we do want, is to only fetch data when the component mounts and we have a neat way of doing it. All we have to do is provide an empty array as a second argument to the effect hook, this will stop it from activating on component updates but only when the component is mounted.

        useEffect(async () => {
            const res = await fetch(url, options);
            const json = await res.json();
            setResponse(json);
        }, []); 
      

      The second is an array containing all the variables on which the hook depends on. If any of the variables change, the hook runs again, but if the argument is an empty array, the hook doesn’t run when updating the component since there are no variables to watch.

      You may have noticed that in the effect hook above, we are using async/await to fetch data. However, according to documentation stipulations, every function annotated with async returns an implicit promise. So in our effect hook, we are returning an implicit promise whereas an effect hook should only return either nothing or a clean-up function.

      So by design, we are already breaking this rule because —

      1. We are not returning nothing
      2. A promise does not clean up anything

      As a result, if we go ahead with the code as is, we will get a warning in the console pointing out the fact that useEffect function must return a cleanup function or nothing.

      Warning: An effect function must not return anything besides a function, which is used for clean-up.
      
      It looks like you wrote useEffect(async () => ...) or returned a Promise. Instead, write the async function inside your effect and call it immediately:
      
      
      useEffect(() => {
        async function fetchData() {
          // You can await here
          const response = await MyAPI.getData(someId);
          // ...
        }
        fetchData();
      }, [someId]); // Or [] if effect doesn't need props or state
      
      Learn more about data fetching with Hooks: https://fb.me/react-hooks-data-fetching
      

      Simply put, using async functions directly in the useEffect() function is frowned at. What we can do to fix this is exactly what is recommended in the warning above. Write the async function and use it inside the effect.

      React.useEffect(() => {
          const fetchData = async () => {
            const res = await fetch(url, options);
            const json = await res.json();
            setResponse(json);
          };
          fetchData();
        }, []);
      

      Instead of using the async function directly inside the effect function, we created a new async function fetchData() to perform the fetching operation and simply call the function inside useEffect. This way, we abide by the rule of returning nothing or just a cleanup function in an effect hook. And if you should check back on the console, you won’t see any more warnings.

      One thing we haven’t mentioned or covered so far is how we can handle error boundaries in this concept. Well, it’s not complicated, when using async/await, it is common practice to use the good old try/catch construct for error handling and thankfully it will also work for us here.

      const useFetch = (url, options) => {
        const [response, setResponse] = React.useState(null);
        const [error, setError] = React.useState(null);
        React.useEffect(() => {
          const fetchData = async () => {
            try {
              const res = await fetch(url, options);
              const json = await res.json();
              setResponse(json);
            } catch (error) {
              setError(error);
            }
          };
          fetchData();
        }, []);
        return { response, error };
      };
      

      Here, we used the very popular JavaScript try/catch syntax to set and handle error boundaries. The error itself is just another state initialized with a state hook so whenever the hook runs, the error state resets. However, whenever there is an error state, the component renders feedback to the user or practically you can perform any desired operation with it.

      You may already know this, but I still feel that it’ll be helpful to point out that you can use hooks to handle loading states for your fetching operations. The good thing is, It’s just another state variable managed by a state hook so if we wanted to implement a loading state in our last example, we’ll set the state variable and update our useFetch() function accordingly.

      const useFetch = (url, options) => {
        const [response, setResponse] = React.useState(null);
        const [error, setError] = React.useState(null);
        const [isLoading, setIsLoading] = React.useState(false);
        React.useEffect(() => {
          const fetchData = async () => {
            setIsLoading(true);
            try {
              const res = await fetch(url, options);
              const json = await res.json();
              setResponse(json);
              setIsLoading(false)
            } catch (error) {
              setError(error);
            }
          };
          fetchData();
        }, []);
        return { response, error, isLoading };
          };
      

      We cannot complete this tutorial without working on a hands-on demonstration to put everything we’ve talked about in practice. Let’s build a mini-app that will fetch a bunch of dog images and their names. We’ll use useFetch to call the very good dog API for the data we’ll need for this app.

      First, we define our useFetch() function which is exactly the same as what we did before. We will simply reuse the one we created while demonstrating error handling above to explain the data fetching concept in practice since it already has most of the things we’ll need.

      const useFetch = (url, options) => {
        const [response, setResponse] = React.useState(null);
        const [error, setError] = React.useState(null);
        React.useEffect(() => {
          const fetchData = async () => {
            try {
              const res = await fetch(url, options);
              const json = await res.json();
              setResponse(json);
            } catch (error) {
              setError(error);
            }
          };
          fetchData();
        }, []);
        return { response, error };
      };
      

      Next, we create the App() function that will actually use our useFetch() function to request for the dog data that we need and display it on screen.

      function App() {
        const res = useFetch("https://dog.ceo/api/breeds/image/random", {});
        if (!res.response) {
          return <div>Loading...</div>
        }
        const dogName = res.response.status
        const imageUrl = res.response.message
        return (
          <div className="App">
            <div>
              <h3>{dogName}</h3>
              <div>
                <img src={imageUrl} alt="avatar" />
              </div>
            </div>
          </div>
        );
      }
      

      Here, we just passed the url into the useFetch() function with an empty options object to fetch the data for the cat. It’s really that simple, nothing elaborate or complex. Once we’ve fetched the data, we just extract it from the response object and display it on screen. Here’s a demo on Codesandbox:

      Data fetching has always been an issue to contend with when building frontend-end applications, this is usually because of all the edge cases that you will need to account for. In this post, we have explained and made a small demo to explain how we can declaratively fetch data and render it on screen by using the useFetch hook with the native fetch() API.