One place for hosting & domains

      Debug

      How To Debug Components, State, and Events with Vue.js Devtools


      The author selected Open Sourcing Mental Illness to receive a donation as part of the Write for DOnations program.

      Introduction

      When debugging a Vue application, it is common to iterate on your code, making changes then restarting the server to see if they fixed the problem in your browser-rendered site. But moving between your source code and your browser can be a time-consuming process. To make debugging more efficient, you can use a browser extension like Vue.js Devtools. Vue.js Devtools is a browser extension for Chrome and Firefox and a stand-alone Electron app created by Guillaume Chau and Evan You of the Vue.js Core Team. It provides the developer with a visual representation of the inner workings of their Vue application so that you can inspect components, data, computed properties, and events from the browser, as well as Vuex actions, getters, and mutations.

      With Devtools, you will be able to see exactly when an event is executed and what payload it has. In addition to events, you will also be able to see all of your components displayed in a DOM-like format where you can analyze component properties, such as data, computed properties, and props.

      In this tutorial, you will set up a sample Vue application, install Vue.js DevTools in your browser, then add new features to your app while testing them with the browser extension. This will serve as a first step to debugging your code with Vue.js Devtools.

      Prerequisites

      Step 1 — Setting Up the Example Application

      In this step, you will put together a sample application that you can use in later steps to try out the Devtools browser extension. To get started, generate a new Vue application via the Vue CLI. To do this, open your terminal window and run the following command.

      • vue create favorite-airports

      When prompted with the setup options for your Vue app, select Manually select features. Then select Choose Vue version, Babel, and Vuex. Once selected, hit the RETURN key and continue filling out the prompts as follows:

      Output

      Vue CLI v4.5.15 ? Please pick a preset: Manually select features ? Check the features needed for your project: Choose Vue version, Babel, Vuex ? Choose a version of Vue.js that you want to start the project with 3.x ? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files ? Save this as a preset for future projects? No

      Once the favorite-airports project is created, open your terminal window and cd into the favorite-airports root folder. Once you’ve changed into the directory, create a new directory with the mkdir command:

      In your text editor of choice, create and open an data/airports.js file and add in the following:

      favorite-airports/src/data/airports.js

      export default [
        {
          name: 'Cincinnati/Northern Kentucky International Airport',
          abbreviation: 'CVG',
          city: 'Hebron',
          state: 'KY',
        },
        {
          name: 'Seattle-Tacoma International Airport',
          abbreviation: 'SEA',
          city: 'Seattle',
          state: 'WA',
        },
        {
          name: 'Minneapolis-Saint Paul International Airport',
          abbreviation: 'MSP',
          city: 'Bloomington',
          state: 'MN',
        },
        {
          name: 'Louis Armstrong New Orleans International Airport',
          abbreviation: 'MSY',
          city: 'New Orleans',
          state: 'LA',
        },
        {
          name: `Chicago O'hare International Airport`,
          abbreviation: 'ORD',
          city: 'Chicago',
          state: 'IL',
        },
        {
          name: `Miami International Airport`,
          abbreviation: 'MIA',
          city: 'Miami',
          state: 'FL',
        }
      ]
      

      This is an array of objects consisting of a few airports in the United States. In this application, you are going to iterate through this data to generate cards consisting of the name, abbreviation, city, and state properties. You will use this data to explore events and dispatches in Vue.js Devtools.

      Save the airports.js file, then create a single-file component (SFC) with the name AirportCard.vue. This file will live in the components directory of your project, and will contain all the styles and logic for the airport card.

      Create and open components/AirportCard.vue in your text editor and add the following:

      favorite-airports/src/components/AirportCard.vue

      <template>
        <div class="airport">
          <p>{{ airport.abbreviation }}</p>
          <p>{{ airport.name }}</p>
          <p>{{ airport.city }}, {{ airport.state }}</p>
        </div>
      </template>
      
      <script>
      export default {
        props: {
          airport: {
            type: Object,
            required: true
          }
        }
      }
      </script>
      
      <style scoped>
      .airport {
        border: 3px solid;
        border-radius: .5rem;
        padding: 1rem;
        margin-bottom: 1rem;
      }
      
      .airport p:first-child {
        font-weight: bold;
        font-size: 2.5rem;
        margin: 1rem 0;
      }
      
      .airport p:last-child {
        font-style: italic;
        font-size: .8rem;
      }
      </style>
      

      You may notice that there is some CSS included in this code snippet. In the AirportCard.vue component, the wrapper <div> contains the class of airport. This CSS adds some styling to the generated HTML by adding borders to give each airport the appearance of a “card”. The :first-child and :last-child are pseudo selectors that apply different styling to the first and last p tags in the HTML inside the div with the class of airport. In addition to that, you may also notice that this component contains a prop, which in Vue.js is a way to pass data down from a parent component to a child component.

      Save and exit from the file.

      Before wrapping up the setup, replace the existing App.vue component with the following code:

      favorite-airports/src/App.vue

      <template>
        <div class="wrapper">
          <div v-for="airport in airports" :key="airport.abbreviation">
            <airport-card :airport="airport" />
          </div>
        </div>
      </template>
      
      <script>
      import { ref } from 'vue'
      import allAirports from '@/data/airports.js'
      import AirportCard from '@/components/AirportCard.vue'
      
      export default {
        components: {
          AirportCard
        },
        setup() {
          const airports = ref(allAirports)
          return { airports }
        }
      }
      </script>
      
      <style>
      #app {
        font-family: Avenir, Helvetica, Arial, sans-serif;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
        text-align: center;
        color: #2c3e50;
        margin-top: 60px;
      }
      
      .wrapper {
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        grid-column-gap: 1rem;
        max-width: 960px;
        margin: 0 auto;
      }
      
      p,
      h3 {
        grid-column: span 3;
      }
      </style>
      

      This code contains a v-for loop that iterates through the airports.js data and renders a series of AirportCard.vue components with airport data passed in via the prop :airport. Save this code and return to the command line.

      With the project set up, run the local development server using the npm run serve command in your terminal:

      This will start a server on your localhost, usually at port 8080. Open your web browser of choice and visit localhost:8080 to see the following:

      A list of cards rendered in Vue using the v-for directive.

      Your example application is now successfully set up. Throughout this tutorial, you are going to use this application to explore the Devtools browser extension.

      In the next step, you are going to install the Vue.js Devtools on Chromium and Firefox browsers.

      Before using the Vue.js Devtools, you will first have to download the program to your computer. This step will focus on installing Devtools in either a Chromium-based browser or Firefox.

      Note: Before you move on, it’s important to note that the example project that you set up in Step 1 is using Vue.js 3. This means, in order for you to use Vue.js Devtools with this newest version of Vue at the time of publishing this tutorial, you will need to install the Beta channel version of Vue.js Devtools.

      Installing on Chromium Browsers

      If you are using a Chromium browser, you can download the Devtools as a Chrome extension. The more common Chromium browsers are Google Chrome, Microsoft Edge, and Opera. If you are using other browsers such as Brave or Vivaldi, this step will work as well.

      To install, first visit the Chrome Web Store. In the search bar in the top-left, search for “Vue Devtools”. You will find a number of results, as shown in the following image:

      The Chrome Web Store search results for

      Make sure you only install Devtools that are offered by Vue.js or “vuejs-dev”, since these are maintained by the official team and are the most trusted solutions. Since you’re app is using Vue 3, you must download the Beta channel offered by “vuejs-dev”.

      Once you click on that, you can view additional information about this extension, including screenshots and an overview, as shown in the following image:

      Description page in the Chrome Web Store for Vue.js Devtools, showing a screenshot of the tool and a blue

      When you are ready, click on the Add to Chrome button in the top-right of the browser. Your browser will then download and install the extension.

      Installing on Firefox

      If you are using Mozilla Firefox, visit the Firefox Extension Store. In the top-right of your browser you will see a search bar. In it, search for “Vue Devtools”, as shown in the following image:

      Firefox Browser Add-Ons page, with

      This will show a number of search results, including an entry published by Evan You:

      Search results for

      Click on the extension that is from “Evan You”. From here, you can view additional information about the extension, including screenshots and an overview:

      Vue.js Devtools page on the Firefox Add-Ons site, with rating information, a screenshot, and a blue button labeled

      Click on the Add to Firefox button to download the extension and install it into your browser.

      Note: If you are using an unsupported browser, such as Safari for example, you can still use Vue.js Devtools as a standalone Electron application via npm. Vue’s DevTool documentation has a page about installing the Devtools as a standalone app to debug an application locally or remotely.

      You now have the Devtools extension installed to your browser. You will see the Vue.js logo where your pinned extensions show up in your browser bar. By default, this logo will be grayed out. But if you visit an application or website that is using Vue, that logo will become colorized with the Vue logo colors.

      In this section, you successfully installed the Devtools on your Chromium or Firefox browser. In the next section, you are going to take a dive into the user interface of the application to view the properties of your AirportCard components from the browser.

      Next, you will navigate through the Devtools interface to inspect the properties of the components in your sample application.

      In Step 1, you started your project on a local development server at localhost:8080. Navigate to that URL in your browser, then right-click or use CMD+ALT+I on a Mac or CTRL+ALT+I in Windows to open your browser inspection tools. In the top bar of your inspector window, there will be a new tab titled Vue. Click on that tab and the Devtools will initialize:

      The Vue tab highlighted in the inspector window.

      Vue.js Devtools initially has two sections: a listing view and a detail view. The listing view contains a list of Vue components or Vuex namespaces. When the Devtools start up, you will see a list of components on the left. Since there are a total of six airport cards displayed in your sample application, there will be six AirportCard components displayed in the listing view, along with the App component.

      In the listing view, select the first App component. The detail view will now provided extra detail about that component. In this case, you will find all of the data and computed properties associated with App.vue, which in this case includes setup with an array of objects representing the airports in airports.js.

      Now click on the first AirportCard directly under App. You will find all of the data and computed properties associated with that instance of the AirportCard.vue component. In this case, it is the CVG card, so it will show properties like abbreviation: "CVG" and state: KY. When hovering over this component, Devtools will also highlight the rendered component in your browser:

      Vue Devtools with the first component selected in the listing view, the component's properties displayed in the detail view, and the component highlighted in the browser display.

      This section showed some basic navigation of the Devtools interface, allowing you to check the properties of components generated in your Vue app. In the next step, you are going to make some changes to the Vue application via the Devtools. With these small edits, you will see how Devtools can be used to test changes to your components.

      With Vue.js Devtools, you can change the properties of your components from the browser, without needing to change your source code. This allows you to debug your application more quickly, without having to adjust your actual code. In this step, you will try this capability out by adding some conditional styling to your AirportCard components and testing it in the browser.

      Currently in your application, there are six different airports. You are going to add some code that will change the color of the card if the airport is under construction. To do this, you will need to navigate to the AirportCard.vue component. You could navigate to it manually, or you can leverage Vue.js Devtools to open this file in your text editor of choice.

      In the browser, with the Devtools window open, click on the crosshairs in the top-right of the development tool. When that is clicked, you can hover over the various airport cards. Devtools will highlight the component in a green color, indicating that the component is selected. When highlighted, click on the card:

      Vue.js Devtools open, with the

      Now that you have your component selected, click on the icon in the top-right that looks like a square with a diagonal arrow. This icon is typically used to notify the user that something will be opened outside of the application. Clicking this will open AirportCard.vue in your editor. With your component file opened, go ahead and add the following highlighted code:

      favorite-airports/src/components/AirportCard.vue

      <template>
        <div class="airport">
          <p>{{ airport.abbreviation }}</p>
          <p>{{ airport.name }}</p>
          <p>{{ airport.city }}, {{ airport.state }}, Under Construction? {{ airport.construction }}</p>
        </div>
      </template>
      ...
      

      This will render the data within the construction property of the airport object. With that complete, add data to the src/data/airports.js file to show if an airport is under construction or not:

      favorite-airports/src/data/airports.js

      export default [
        {
          name: 'Cincinnati/Northern Kentucky International Airport',
          ...
          construction: false
        },
        {
          name: 'Seattle-Tacoma International Airport',
          ...
          construction: false
        },
        {
          name: 'Minneapolis-Saint Paul International Airport',
          ...
          construction: false
        },
        {
          name: 'Louis Armstrong New Orleans International Airport',
          ...
          construction: false
        },
        {
          name: `Chicago O'hare International Airport`,
          ...
          construction: false
        },
        {
          name: `Miami International Airport`,
          ...
          construction: false
        }
      ]
      

      Save and close this data file.

      With your data added to your application, you will now write some CSS to add a class if the construction property is true. Open the AirportCards.vue component to add the following:

      favorite-airports/src/components/AirportCard.vue

      <template>
        <div class="airport" :class="{ 'is-under-construction': airport.construction }">
          <p>{{ airport.abbreviation }}</p>
          <p>{{ airport.name }}</p>
          <p>{{ airport.city }}, {{ airport.state }}, Under Construction? {{ airport.construction }}</p>
        </div>
      </template>
      
      <style scoped>
      ...
      .airport.is-under-construction {
        border-color: red;
        color: red;
      }
      </style>
      

      On the <div> with the airport class, you are binding an object to the class attribute. The key of this object is the class that will be applied, and the property is the condition that needs to be met before applying the class. The CSS in the <style> tags changes the border and the text color of the card to red if the class is-under-construction is applied to the card.

      Now open your browser and open the Vue.js Devtools. In the left pane, highlight the <App> component. On the right column, the setup method and its properties will be displayed. You will find an array of airports. Expand that array, then expand one of the objects in it. Open the first object with the abbreviation CVG. To test if this code works, click on the pencil icon of the construction data property and change it to true.

      Vue Devtools opened to modify the CVG card to have a true value for construction. The corresponding card in the browser window is red.

      Once you press ENTER or click on the save icon, that data will be updated in the frontend. The card will immediately change to red. If you were to inspect the element and review the DOM, you would find that the is-under-construction class has been applied to the first airport card.

      Now that you’ve tried out changing properties in Devtools to test your application logic, you will next see how to test emitted events from the browser.

      In addition to debugging a component’s data and properties, you can also use Devtools to debug built-in and custom events. Vue.js Devtools provides tools for visualizing events and their payloads.

      To try out testing an event, you will first add an event to your AirportCard component. When you click on an airport card, the app will emit an event to the parent component (App.vue) with the airport data that you clicked.

      Open your text editor, and in the AirportCard.vue component, add the following click event with an $emit on the outermost <div>:

      favorite-airports/src/components/AirportCard.vue

      <template>
        <div class="airport" :class="{ 'is-under-construction': airport.construction }" @click="$emit('favorite-airport', airport)">
          <p>{{ airport.abbreviation }}</p>
          <p>{{ airport.name }}</p>
          <p>{{ airport.city }}, {{ airport.state }}, Under Construction? {{ airport.construction }}</p>
        </div>
      </template>
      ...
      

      On the outermost <div>, you are invoking a JavaScript click event. In that click event, you are firing off a custom event called favorite-airport. The payload for that event is the data associated with the airport variable from the v-for loop.

      Save the changes to your AirportCard component.

      Next, open up Vue.js Devtools in your browser. In the top bar to the right of the compass icon (inspector) is the timeline inspector. Click on the icon to open up the Devtools timeline:

      Animation showing a mouse cursor clicking the event timeline view in Vue.js Devtools.

      This timeline inspector lets you inspect any event, keyboard stroke, mutation, and more that happens over a period of time. With the tools open, click on one of the airport cards in the browser viewport. Once you do that, you will see a series of dots on your timeline:

      Vue Devtools event timeline view showing a series of purple and green dots in lines parallel to each other.

      These dots represent various events that happen behind the scenes, including the mousedown and mouseup events that were executed on your click. Mouse events will always be highlighted in purple. The green dot is your custom event that you set up to fire on the click event. Click on the green dot to find more information regarding that event, as shown in the following image:

      Two extra panes of the Vue.js Devtools timeline view that show a log of component events and information about the event, including its name, component, and parameters.

      In this pane, you can see when the event was executed, as well as the data that was passed up to the parent. In this case, the payload of the event was the Chicago airport with the code ORD. This shows that your event fired correctly, allowing you to continue to use this event to develop additional features. In the next step, you will use this event to store the payload data in a Vuex store to keep track of a user’s favorite airports.

      In Vue.js Devtools, there is a specific pane set aside for monitoring Vuex actions, mutations, and stored state. By using this view, you can inspect your state for problems without having to iterate through source code changes. In this section, you will implement Vuex to make a list of favorite airports that a user can add to by clicking the airport card. You will then monitor these features with Vue.js Devtools.

      With your custom event created and executing, you will now take that data and call a Vuex action and mutation with it. If you are not familiar with Vuex, it is recommended to read more about it in our Vuex tutorial.

      In your text editor, open the src/store/index.js file and add the following code:

      favorite-airports/src/store/index.js

      import { createStore } from 'vuex'
      
      export default createStore({
        state: {
          favorites: [],
        },
        mutations: {
          UPDATE_FAVORITES(state, payload) {
            state.favorites = payload
          }
        },
        actions: {
          addToFavorites({ state, commit }, payload) {
            const airports = state.favorites
            airports.push(payload)
            commit('UPDATE_FAVORITES', airports)
          }
        }
      })
      

      In this snippet, you are adding to the index.js file that was generated in Step 1. Specifically, you are adding a favorites state property (an array of airports.js objects), a mutation called UPDATE_FAVORITES, and an action called addToFavorites. The intent is for the user to click on a card, which will fire the action, which will fire the mutation, which will then update the store.

      In your App.vue component, add the following code to dispatch an action when your custom favorite-airport event is executed:

      favorite-airports/src/App.vue

      <template>
        <div class="wrapper">
          <div v-for="airport in airports" :key="airport.abbreviation">
            <airport-card :airport="airport" @favorite-airport="$store.dispatch('addToFavorites', $event)"/>
          </div>
        </div>
      </template>
      
      <script>
      import { ref } from 'vue'
      import allAirports from '@/data/airports.js'
      import AirportCard from '@/components/AirportCard.vue'
      
      export default {
        components: {
          AirportCard
        },
        setup() {
          const airports = ref(allAirports)
          return { airports }
        }
      }
      </script>
      ...
      

      With your Vuex properties added, open your browser and open the Devtools. In the Components dropdown at the top of the pane, you will now find a Vuex option. Click to switch to the Vuex view.

      The Vuex dropdown in the Vue Devtools

      Similar to the Components section, the left panel is a visualization of your state tree, complete with namespaced modules and any root state that you might have. To the right is a full list of data in that module or section of your Vuex state.

      In the right panel, you will find an empty array of favorites. Now click on a few cards and see each airport object get pushed into that array:

      Animation showing airports being added to a favorites list in the Vuex store.

      Now that you know that the state is working, you can expand on this by adding an additional section to the App.vue file:

      favorite-airports/src/App.vue

      <div class="wrapper">
          <div v-for="airport in airports" :key="airport.abbreviation">
            <airport-card :airport="airport" @favorite-airport="$store.dispatch('addToFavorites', $event)"/>
          </div>
      
        <div v-if="$store.state.favorites.length">
          <h1>Favorites <template v-if="$store.state.favorites.length">({{ $store.state.favorites.length }})</template></h1>
          <div v-for="airport in $store.state.favorites" :key="airport.abbreviation">
            <airport-card :airport="airport" />
          </div>
        </div>
      </div>
      ...
      

      Save the file, then click on a card in your browser. A new section will be displayed with cards of the airports that have been added.

      The Vue application rendered in a browser, with a list of favorite airports beneath the airport cards.

      Conclusion

      Vue.js Devtools is a free browser extension that you can add to any Chromium or Firefox broswer. You can also download it and as a standalone application that can be tied to your application. In this tutorial, you built an application from a dataset that rendered a number of card components, each with their own data. You then used Devtools to examine the properties of the components, change properties to test conditional style changes, test to see if events fired appropriately, and ensured that Vuex state management was set up correctly.

      To learn more about Vue.js Devtools, you can visit the official Vue DevTools documentation. For more tutorials on Vue, check out the How To Develop Websites with Vue.js series page.



      Source link

      How To Debug React Components Using React Developer Tools


      The author selected Creative Commons to receive a donation as part of the Write for DOnations program.

      Introduction

      Since React apps are made to scale and grow quickly, it’s easy for subtle bugs to infiltrate your code. The React Developer Tools browser extension can help you track down these bugs by giving you more insight into the current state for each component. React Developer Tools gives you an interface for exploring the React component tree along with the current props, state, and context for individual components. React Developer Tools also lets you determine which components are re-rendering and can generate graphs to show how long individual components take to render. You can use this information to track down inefficient code or to optimize data-heavy components.

      This tutorial begins by installing the React Developer Tools browser extension. You’ll then build a text analyzer as a test application, which will take a block of text and display information such as word count, character count, and character usage. Finally, you will use React Developer Tools to explore the text analyzer’s components and keep track of the changing props and context. The examples will use the Chrome browser, but you can also use the plugin for Firefox.

      By the end of this tutorial, you’ll be able to start using the React Developer Tools to debug and explore any React project.

      Prerequisites

      In this step, you’ll install the React Developer Tools broswer extension in Chrome. You’ll use the developer tools in the Chrome JavaScript console to explore the component tree of the debug-tutorial project you made in the Prerequisites. This step will use Chrome, but the steps will be nearly identical for installing the React Developer Tools as an add-on in Firefox.

      By the end of this step, you’ll have the React Developer Tools installed in your browser and you’ll be able to explore and filter components by name.

      The React Developer Tools is a plugin for the Chrome and Firefox browser. When you add the extension, you are adding additional tools to the developer console. Visit the Chrome plugin page for React Developer Tools to install the extension.

      Click on the Add to Chrome button. Then click on the Add extension button to confirm:

      Chrome add extension button

      Chrome will install the extension, and a success message and a new icon will appear in the upper right corner of your browser next to the address bar:

      Chrome success message

      If the icon does not appear, you can add it by clicking on the puzzle piece, then clicking on the pushpin icon by the React Developer Tools:

      Pin extension

      When you are on a page that does not have any React components, the icon will appear gray. However, if you are on a page with React components, the icon will appear blue and green. If you click on the icon, it will indicate that the application is running a production version of React.

      Visit digitalocean.com, to find that the homepage is running a production version of React:

      DigitalOcean React Production Build information

      Now that you are on a website that uses React, open the console to access the React Developer Tools. Open the console by either right-clicking and inspecting an element or by opening the toolbar by clicking View > Developer > JavaScript console.

      When you open the console, you’ll find two new tabs: Components and Profiler:

      Console Open

      The Components tab will show the current React component tree, along with any props, state, or context. The Profiler tab lets you record interactions and measure component rendering. You’ll explore the Profiler tab in Step 3.

      Click on the Components tab to see the current component tree.

      Since this is a production build, the code will be minified and the components will not have descriptive names:

      Components for digitalocean.com in the console

      Now that you’ve tried out React Developer Tools on a working website, you can use it on your test application. If you haven’t started your debug-tutorial application yet, go to a terminal window and run npm start from the root of the project.

      Open a browser to http://localhost:3000.

      Notice that the icon for React Developer Tools is now red and white. If you click on the React Developer Tools icon, you’ll see a warning that the page is in development mode. Since you are still working on the sample application, this is expected.

      Open the console and you’ll find the name of the App component in the Components tab.

      Base Component

      There’s not a lot of information yet, but as you build out the project in the next step, you’ll see all of your components forming a navigable tree.

      In this step, you added the React Developer Tools extension to Chrome. You activated the tools on both a production and a development page, and you briefly explored your debug-tutorial project in the Components tab. In the next step, you’ll build the text analyzer that you’ll use to try out the features of the React Developer Tools.

      Step 2 — Identifying Real-Time Component Props and Context

      In this step, you’ll build a small application to analyze a block of text. The app will determine and report the word count, character count, and character frequency of the text in the input field. As you build the application, you’ll use React Developer Tools to explore the current state and props of each component. You’ll also use React Developer Tools to view the current context in deeply nested components. Finally, you’ll use the tools to identify components that re-render as state changes.

      By the end of this step, you’ll be able to use the React Developer Tools to explore a live application and to observe the current props and state without console statements or debuggers.

      To start, you will create an input component that will take a large amount of text.

      Open the App.js file:

      • nano src/components/App/App.js

      Inside the component, add a div with a class of wrapper, then create a <label> element surrounding a <textarea> element:

      debug-tutorial/src/components/App/App.js

      import React from 'react';
      import './App.css';
      
      function App() {
        return(
          <div className="wrapper">
           <label htmlFor="text">
             Add Your Text Here:
             <br>
             <textarea
               id="text"
               name="text"
               rows="10"
               cols="100"
             >
             </textarea>
            </label>
          </div>
        )
      }
      
      export default App;
      

      This will be the input area for your user. The htmlFor attribute links the label element to elements with an id of text using JSX. You also give the <textarea> component 10 rows and 100 columns to provide room for a large amount of text.

      Save and close the file. Next, open App.css:

      • nano src/components/App/App.css

      Add some styling to the application by replacing the contents with the following:

      debug-tutorial/src/components/App.App.css

      .wrapper {
          padding: 20px;
      }
      
      .wrapper button {
          background: none;
          border: black solid 1px;
          cursor: pointer;
          margin-right: 10px;
      }
      
      .wrapper div {
          margin: 20px 0;
      }
      

      Here you add some padding to the wrapper class, then simplify child <button> elements by removing the background color and adding some margin. Finally, you add a small margin to child <div> elements. These styles will apply to components you will build to display information about the text.

      Save the file. When you do, the browser will refresh and you’ll see the input:

      Text area

      Open App.js:

      • nano src/components/App/App.js

      Next, create a context to hold the value from the <textarea> element. Capture the data using the useState Hook:

      debug-tutorial/src/components/App/App.js

      import React, { createContext, useState } from 'react';
      import './App.css';
      
      export const TextContext = createContext();
      
      function App() {
        const [text, setText] = useState('');
      
        return(
          <TextContext.Provider value={text}>
            <div className="wrapper">
              <label htmlFor="text">
                Add Your Text Here:
                <br>
                <textarea
                  id="text"
                  name="text"
                  rows="10"
                  cols="100"
                  onChange={e => setText(e.target.value)}
                >
                </textarea>
              </label>
            </div>
          </TextContext.Provider>
        )
      }
      
      export default App;
      

      Be sure to export TextContext, then wrap the whole component with the TextContext.Provider. Capture the data by adding an onChange prop to your <textarea> element.

      Save the file. The browser will reload. Be sure that you have React Developer Tools open and notice that App component now shows theContext.Provider as a child component.

      Component context in React Developer Tools

      The component by default has a generic name—Context—but you can change that by adding a displayName property to the generated context. Inside App.js, add a line where you set the displayName to TextContext:

      debug-tutorial/src/components/App/App.js

      import React, { createContext, useState } from 'react';
      import './App.css';
      
      export const TextContext = createContext();
      TextContext.displayName="TextContext";
      
      function App() {
          ...
      }
      
      export default App;
      

      It is not necessary to add a displayName, but it does help to navigate components when analyzing the component tree in the console. You will also see the value of the useState Hook in the side bar. Type some text in the input and you’ll see the updated value in React Developer Tools under the hooks section on the App component.

      Update Value in Developer Tools

      The Hook also has a generic name of State, but this is not as easy to update as the context. There is a useDebugValue Hook, but it only works on custom Hooks and is not recommended for all custom Hooks.

      In this case, the state for the App component is the prop to TextContext.Provider. Click on the TextContext.Provider in the React Developer Tools and you’ll see that the value also reflects the input value that you set with the state:

      Updated value for the context

      React Developer Tools is showing you real time prop and context information, and the value will grow as you add components.

      Next, add a component called TextInformation. This component will be a container for the components with specific data analysis, such as the word count.

      First, make the directory:

      • mkdir src/components/TextInformation

      Then open TextInformation.js in your text editor.

      • nano src/components/TextInformation/TextInformation.js

      Inside the component, you will have three separate components: CharacterCount, WordCount, and CharacterMap. You’ll make these components in just a moment.

      The TextInformation component will use the useReducer Hook to toggle the display of each component. Create a reducer function that toggles the display value of each component and a button to toggle each component with an onClick action:

      debug-tutorial/src/components/TextInformation/TextInformation.js

      import React, { useReducer } from 'react';
      
      const reducer = (state, action) => {
        return {
          ...state,
          [action]: !state[action]
        }
      }
      export default function TextInformation() {
        const [tabs, toggleTabs] = useReducer(reducer, {
          characterCount: true,
          wordCount: true,
          characterMap: true
        });
      
        return(
          <div>
            <button onClick={() => toggleTabs('characterCount')}>Character Count</button>
            <button onClick={() => toggleTabs('wordCount')}>Word Count</button>
            <button onClick={() => toggleTabs('characterMap')}>Character Map</button>
          </div>
        )
      }
      

      Notice that your useReducer Hook starts with an object that maps each key to a boolean. The reducer function uses the spread operator to preserve the previous value while setting a new value using the action parameter.

      Save and close the file. Then open App.js:

      • nano src/components/App/App.js

      Add in your new component:

      debug-tutorial/src/components/App/App.js

      import React, { createContext, useState } from 'react';
      import './App.css';
      import TextInformation from '../TextInformation/TextInformation';
      
      ...
      
      function App() {
        const [text, setText] = useState('');
      
        return(
          <TextContext.Provider value={text}>
            <div className="wrapper">
              <label htmlFor="text">
                Add Your Text Here:
                <br>
                <textarea
                  id="text"
                  name="text"
                  rows="10"
                  cols="100"
                  onChange={e => setText(e.target.value)}
                >
                </textarea>
              </label>
              <TextInformation />
            </div>
          </TextContext.Provider>
        )
      }
      
      export default App;
      

      Save and close the file. When you do, the browser will reload, and you’ll see the updated component. If you click on TextInformation in React Developer Tools, you’ll see the value update on each button click:

      Update Reducer on Click

      Now that you have the container component, you’ll need to create each informational component. Each component will take a prop called show. If show is falsy, the component will return null. The components will consume the TextContext, analyze the data, and display the result.

      To start, create the CharacterCount component.

      First, make a new directory:

      • mkdir src/components/CharacterCount

      Then, open CharacterCount.js in your text editor:

      • nano src/components/CharacterCount/CharacterCount.js

      Inside the component, create a function that uses the show prop and displays null if show is falsy:

      debug-tutorial/src/components/CharacterCount/CharacterCount.js

      import React, { useContext } from 'react';
      import PropTypes from 'prop-types';
      import { TextContext } from '../App/App';
      
      export default function CharacterCount({ show }) {
        const text = useContext(TextContext);
      
        if(!show) {
          return null;
        }
      
        return(
          <div>
            Character Count: {text.length}
          </div>
        )
      }
      
      CharacterCount.proTypes = {
        show: PropTypes.bool.isRequired
      }
      

      Inside the CharacterCount function, you assign the value of TextContext to a variable using the useContext Hook. You then return a <div> that shows the character count using the length method. Finally, PropTypes adds a weak typing system to provide some enforcement to make sure the wrong prop type is not passed.

      Save and close the file. Open TextInformation.js:

      • nano src/components/TextInformation/TextInformation.js

      Import CharacterCount and add the component after the buttons, passing tabs.characterCount as the show prop:

      debug-tutorial/src/components/TextInformation/TextInformation.js

      import React, { useReducer } from 'react';
      import CharacterCount from '../CharacterCount/CharacterCount';
      
      const reducer = (state, action) => {
        return {
          ...state,
          [action]: !state[action]
        }
      }
      
      export default function TextInformation() {
        const [tabs, toggleTabs] = useReducer(reducer, {
          characterCount: true,
          wordCount: true,
          characterMap: true
        });
      
        return(
          <div>
            <button onClick={() => toggleTabs('characterCount')}>Character Count</button>
            <button onClick={() => toggleTabs('wordCount')}>Word Count</button>
            <button onClick={() => toggleTabs('characterMap')}>Character Map</button>
            <CharacterCount show={tabs.characterCount} />
          </div>
        )
      }
      

      Save the file. The browser will reload and you’ll see the component in the React Developer Tools. Notice that as you add words in the input, the context will update. If you toggle the component, you’ll see the props update after each click:

      Adding text and toggling

      You can also manually add or change a prop by clicking on the property and updating the value:

      Manually Changing Props

      Next, add a WordCount component.

      Create the directory:

      • mkdir src/components/WordCount

      Open the file in a text editor:

      • nano src/components/WordCount/WordCount.js

      Make a component that is similar to CharacterCount, but use the split method on spaces to create an array of words before showing the length:

      debug-tutorial/src/components/WordCount/WordCount.js

      import React, { useContext } from 'react';
      import PropTypes from 'prop-types';
      import { TextContext } from '../App/App';
      
      export default function WordCount({ show }) {
        const text = useContext(TextContext);
      
        if(!show) {
          return null;
        }
      
        return(
          <div>
            Word Count: {text.split(' ').length}
          </div>
        )
      }
      
      WordCount.proTypes = {
        show: PropTypes.bool.isRequired
      }
      

      Save and close the file.

      Finally, create a CharacterMap component. This component will show how often a specific character is used in a block of text. It will then sort the characters by frequency in the passage and display the results.

      First, make the directory:

      • mkdir src/components/CharacterMap

      Next, open CharacterMap.js in a text editor:

      • nano src/components/CharacterMap/CharacterMap.js

      Import and use the TextContext component and use the show prop to display results as you did in the previous components:

      debug-tutorial/src/components/CharacterMap/CharacterMap.js

      import React, { useContext } from 'react';
      import PropTypes from 'prop-types';
      import { TextContext } from '../App/App';
      
      export default function CharacterMap({ show }) {
        const text = useContext(TextContext);
      
        if(!show) {
          return null;
        }
      
        return(
          <div>
            Character Map: {text.length}
          </div>
        )
      }
      
      CharacterMap.proTypes = {
        show: PropTypes.bool.isRequired
      }
      

      This component will need a slightly more complicated function to create the frequency map for each letter. You’ll need to go through each character and increment a value anytime there is a repeat. Then you’ll need to take that data and sort it so that the most frequent letters are at the top of the list.

      To do this, add the following highlighted code:

      debug-tutorial/src/components/CharacterMap/CharacterMap.js

      
      import React, { useContext } from 'react';
      import PropTypes from 'prop-types';
      import { TextContext } from '../App/App';
      
      function itemize(text){
       const letters = text.split('')
         .filter(l => l !== ' ')
         .reduce((collection, item) => {
           const letter = item.toLowerCase();
           return {
             ...collection,
             [letter]: (collection[letter] || 0) + 1
           }
         }, {})
       return Object.entries(letters)
         .sort((a, b) => b[1] - a[1]);
      }
      
      export default function CharacterMap({ show }) {
        const text = useContext(TextContext);
      
        if(!show) {
          return null;
        }
      
        return(
          <div>
           Character Map:
           {itemize(text).map(character => (
             <div key={character[0]}>
               {character[0]}: {character[1]}
             </div>
           ))}
          </div>
        )
      }
      
      CharacterMap.proTypes = {
        show: PropTypes.bool.isRequired
      }
      

      In this code, you create a function called itemize that splits the text into an array of characters using the split() string method. Then you reduce the array to an object by adding the character and then incrementing the count for each subsequent character. Finally, you convert the object to an array of pairs using Object.entries and sort to put the most used characters at the top.

      After you create the function, you pass the text to the function in the render method and map over the results to display the character—array value [0]—and the count—array value [1]—inside a <div>.

      Save and close the file. This function will give you an opportunity to explore some performance features of the React Developer Tools in the next section.

      Next, add the new components to TextInformation and look at the values in React Developer Tools.

      Open TextInformation.js:

      • nano src/components/TextInformation/TextInformation.js

      Import and render the new components:

      debug-tutorial/src/components/TextInformation/TextInformation.js

      import React, { useReducer } from 'react';
      import CharacterCount from '../CharacterCount/CharacterCount';
      import CharacterMap from '../CharacterMap/CharacterMap';
      import WordCount from '../WordCount/WordCount';
      
      const reducer = (state, action) => {
        return {
          ...state,
          [action]: !state[action]
        }
      }
      
      export default function TextInformation() {
        const [tabs, toggleTabs] = useReducer(reducer, {
          characterCount: true,
          wordCount: true,
          characterMap: true
        });
      
        return(
          <div>
            <button onClick={() => toggleTabs('characterCount')}>Character Count</button>
            <button onClick={() => toggleTabs('wordCount')}>Word Count</button>
            <button onClick={() => toggleTabs('characterMap')}>Character Map</button>
            <CharacterCount show={tabs.characterCount} />
            <WordCount show={tabs.wordCount} />
            <CharacterMap show={tabs.characterMap} />
          </div>
        )
      }
      

      Save and close the file. When you do, the browser will refresh, and if you add in some data, you’ll find the character frequency analysis in the new components:

      CharacterMap Component in React Developer Tools

      In this section, you used React Developer Tools to explore the component tree. You also learned how to see the real-time props for each component and how to manually change the props using the developer tools. Finally, you viewed the context for the component change with input.

      In the next section, you’ll use the React Developer Tools Profiler tab to identify components that have long render times.

      Step 3 — Tracking Component Rendering Across Interactions

      In this step, you’ll use the React Developer Tools profiler to track component rendering and re-rendering as you use the sample application. You’ll navigate flamegraphs, or visualizations of your app’s relevant optimization metrics, and use the information to identify inefficient components, reduce rendering time, and increase application speed.

      By the end of this step, you’ll know how to identify components that render during user interactions and how to compose components to reduce inefficient rendering.

      A quick way to see how components change each other is to enable highlighting when a component is re-rendered. This will give you a visual overview of how the components respond to changing data.

      In React Developer Tools, click on the Settings icon. It will look like a gear:

      Settings icon

      Then select the option under General that says Highlight updates when components render.

      Highlight changes

      When you make any changes, React Developer Tools will highlight components that re-render. For example, when you change input, every component re-renders because the data is stored on a Hook at the root level and every change will re-render the whole component tree.

      Notice the highlighting around the components, including the top of the screen around the root component:

      Highlighting Text

      Compare that to how the components re-render when you click on one of the buttons to toggle the data. If you click one of the buttons, the components under TextInformation will re-render, but not the root component:

      Rerendering lower components only

      Showing the re-renders will give you a quick idea of how the components are related, but it doesn’t give you a lot of data to analyze specific components. To gain more insight, let’s look at the profiler tools.

      The profiler tools are designed to help you measure precisely how long each component takes to render. This can help you identify components that may be slow or process intense.

      Re-open the settings and uncheck the box for Highlight updates when components render. Then click on the Profiler tab in the console.

      To use the profiler, click the blue circle on the left of the screen to begin recording and click it again when you are finished:

      Start profiling

      When you stop recording, you’ll find a graph of the component changes including, how long each item took to render.

      To get a good sense of the relative efficiency of the components, paste in the Wikipedia page for Creative Commons. This text is long enough to give interesting results, but not so big that it will crash the application.

      After pasting in the text, start the profiler, then make a small change to the input. Stop profiling after the component has finished re-rendering. There will be a long pause, because the application is handling a long re-rendering:

      Adding a change with a lot of text

      When you end the recording, React Developer Tools will create a flamegraph that shows every component that re-rendered and how long it took to re-render each component.

      In this case, every keypress from the word “Change” causes a re-render. More importantly, it shows how long each render takes and why there was a long delay. The components App, TextContext.Provider, and TextInformation take about .2 milliseconds to rerender. But the CharacterMap component takes around 1 second per keystroke to re-render because of the complicated data parsing in the itemize function.

      In the display, each yellow bar is a new keystroke. You can replay the sequence one at a time by clicking on each bar. Notice that there is slight variation in the render times, but the CharacterMap is consistently slow:

      Looking at the flamegraph

      You can get more information by selecting the option Record why each component rendered while profiling. under the Profiler section of the settings.

      Try toggling the Word Count component and notice how long the changes take. The application still lags even though you haven’t changed the text content:

      Word Count toggle flamegraph

      Now when you hover your cursor over a component, you’ll find that it includes a reason the component re-rendered. In this case, the reason the component changed is The parent component rendered. That’s a problem for the CharacterMap component. CharacterMap is doing an expensive calculation every time the parent changes, even if the props and the context do not change. That is, it’s recalculating data even though the data is identical to the previous render.

      Click on the Ranked tab and you’ll find how much more time CharacterMap takes when compared to all other components:

      Ranked Tab

      React Developer Tools have helped isolate a problem: the CharacterMap component re-renders and performs an expensive calculation anytime any parent component changes.

      There are multiple ways to solve the problem, but they all involve some sort of caching via memoization, a process by which already calculated data is remembered rather than recalculated. You can either use a library like lodash/memoize or memoize-one to cache the results of the itemize function, or you can use the built in React memo function to memoize the whole component.

      If you use the React memo, the function will only re-render if the props or context change. In this case, you’ll use React memo. In general, you should memoize the data itself first since it’s a more isolated case, but there are some interesting changes in the React Developer Tools if you memoize the whole component, so you’ll use that approach in this tutorial.

      Open CharacterMap.js:

      • nano src/components/CharacterMap/CharacterMap.js

      Import memo from React, then pass the entire function into the memo function:

      debug-tutorial/src/components/CharacterMap/CharacterMap.js

      import React, { memo, useContext } from 'react';
      import PropTypes from 'prop-types';
      import { TextContext } from '../App/App';
      
      ...
      
      function CharacterMap({ show }) {
        const text = useContext(TextContext);
      
        if(!show) {
          return null;
        }
      
        return(
          <div>
           Character Map:
           {itemize(text).map(character => (
             <div key={character[0]}>
               {character[0]}: {character[1]}
             </div>
           ))}
          </div>
        )
      }
      
      CharacterMap.proTypes = {
        show: PropTypes.bool.isRequired
      }
      
      export default memo(CharacterMap);
      
      

      You move the export default line to the end of the code in order to pass the component to memo right before exporting. After that, React will compare the props before re-rendering.

      Save and close the file. The browser will reload, and when you toggle the WordCount, the component will update much faster. This time, CharacterMap does not re-render. Instead, in React Developer Tools, you’ll see a gray rectangle showing re-rendering was prevented.

      React Developer Tools showing that CharacterMap did not re-render

      If you look at the Ranked tab, you’ll find that both the CharacterCount and the WordCount re-rendered, but for different reasons. Since CharacterCount is not memoized, it re-rendered because the parent changed. The WordCount re-rendered because the props changed. Even if it was wrapped in memo, it would still rerender.

      Ranked view of memoized app

      Note: Memoizing is helpful, but you should only use it when you have a clear performance problem, as you did in this case. Otherwise, it can create a performance problem: React will have to check props every time it re-renders, which can cause a delay on smaller components.

      In this step, you used the profiler to identify re-renders and componenent re-rendering. You also used flamegraphs and ranked graphs to identify components that are slow to re-render and then used the memo function to prevent re-rendering when there are no changes to the props or context.

      Conclusion

      The React Developer Tools browser extension gives you a powerful set of utilities to explore your components in their applications. With these tools, you’ll be able to explore a component’s state and identify bugs using real data without console statements or debuggers. You can also use the profiler to explore how components interact with each other, allowing you to identify and optimize components that have slow rendering in your full application. These tools are a crucial part of the development process and give you an opportunity to explore the components as part of an application and not just as static code.

      If you would like to learn more about debugging JavaScript, see our article on How To Debug Node.js with the Built-In Debugger and Chrome DevTools. For more React tutorials, check out our React Topic page, or return to the How To Code in React.js series page.



      Source link

      3 Ways to Debug Tech’s Diversity Gap in 2020


      Silicon Valley is struggling with a bit of an image problem. That image? Straight, white, male.

      In 2018, women filled only 25% of all computing-related occupations — which is about the same percentage that we saw in the 1960s. For African-American and Hispanic populations, the representation in these fields is far below the national distribution.

      And at the intersection of race and gender, the state of women in tech is even bleaker: 65% of women in computing occupations are white, 19% are Asian/Pacific Islander, only 7% are African American, and 7% are Latina.

      In 2019, computer programmers are no longer high-school geeks, but meritocratic winners who wield considerable power in society. Engineers at Facebook — or more precisely, the algorithms they program — decide what news we see and what ads we get served.

      (If you think that ads aren’t linked to economic opportunity, think again.)

      Many formerly analog tasks — hailing a taxi, dimming the lights — now rely on code that only programmers can hope to understand fully. If women and minorities are left out of coding jobs now, that omission could have ramifications on the structure of our society for years to come.

      It’s clear by now that social and environmental forces contribute to the differences in earning potential for women and minorities, and that these forces also hold the same people back from careers in STEM (Science, Technology, Engineering, and Math). What needs to be done? Let’s take a look at how to debug the diversity gap.

      DreamHost Takes Inclusivity Seriously

      We regularly report on diversity, accessibility, and representation in the tech workforce. Subscribe to our monthly newsletter so you never miss an article.

      1. Give Every Student Access to Computer Science Classes

      Early exposure to skills is crucial for securing a job in one of the best-paid and fastest-growing industries around. Yet only 35% of high schools nationwide are currently teaching computer science classes. Some schools in the U.S. are exposing young people to the basics of programming, which serves to improve their familiarity and comfort with these subjects. But to open the doors of the tech meritocracy to the underprivileged, coding needs to be taught in public schools, as early as possible — even in elementary school.

      There are a lot of barriers to this.

      Because the public education system in the U.S. depends heavily on local control, it’s impossible to design and implement sweeping changes to curricula in one fell swoop. National standards like Common Core and testing-focused federal programs like No Child Left Behind often leave little room for enrichment classes or electives.

      In some cases, nonprofits and businesses are stepping in to fill the gap; for instance, this year Google pledged $25 million to support programs that help Black and Latino students have access to computer science education. But a charity initiative here or there isn’t likely to create broad-based change.

      It also won’t be enough for schools just to offer coding classes: the coding gap will only close with specific outreach to marginalized groups. There is substantial data to suggest that a learned lack of confidence can discourage minority groups from choosing certain subjects in school. And one 2016 study found that boys and girls begin school achieving in math at similar rates, with a gender gap appearing as early as third grade — this is significant, as previous research suggests that early achievement in math predicts interest and confidence in the subject in middle and high school.

      Even more concerning, the study indicated that elementary school teachers perceive girls with nearly identical math scores (and classroom behavior) to be less proficient in math than boys.

      This unconscious bias contributes to female students lacking confidence and performing worse in future math classes.  Unless teachers work to recruit girls and minorities to coding classes and overcome their own perceptions that girls aren’t as good at math, such biases will continue to keep their numbers in the tech sector low.

      2. Expand the Scope of Nonprofits

      We’ve certainly been entering the Era of the Nonprofit for the past few years, and nonprofits that aim to teach coding to women and people of color abound. (A few examples: #YesWeCode. Girls Who Code. Black Girls Code.)

      Lack of access to training isn’t the only issues these groups face. In the case of underprivileged youth, for instance, a major challenge is the limited access some of these underrepresented students have to computers.

      But the challenges extend beyond the physical, especially when it comes to connecting students with jobs that utilize their training. Limitations experienced in this realm — such as the absence of a professional network or an unfriendly corporate culture — can prevent any would-be software engineer or developer from thriving. Successful nonprofit coding programs will be those that succeed in the final stretch: job placement, hiring, and support during the transition.

      3. Retain Diverse Talent in the Workplace

      It’s not just a lack of candidates in the pipeline that’s keeping representation low; it’s also a lack of retention. Support needs to continue after coders become established in their careers. At 10 to 20 years into their tech careers,  56% of women leave the field, at a quit-rate double that of men.

      Why are they leaving? One small study found that the most common reasons women leave tech jobs are a lack of opportunity for career growth, poor management, and the gender pay gap. Older research cites poor workplaces including few opportunities for development and training, little support for outside-of-work responsibilities, and undermining bosses.

      A 2019 study published in Nature found that nearly half of women in science leave after having their first child, compared to 23% of men. Clearly, something needs to be done to better support parents in STEM fields, particularly working mothers.

      There are a number of ways to support and retain female and minority coders, starting with simply calling out their accomplishments and good ideas. Nonprofits that encourage professional networking, like Women Who Code, can certainly help women find their tribe in the industry, but in the end, it will be up to tech companies themselves to enact policies to retain female talent.

      The Reality of the Diversity Gap in the Tech World

      The tech industry is booming, which, in theory, should mean more demand for programming labor. But with barriers to intercontinental communication quickly vanishing, more and more programming and web-design jobs based in the U.S. are being outsourced to lower-paid workers in other countries. In fact, computer programming jobs are projected to decrease by 7% over the next eight years in the U.S., even as the computer technology industry is expected to grow by 12%.

      Whether computer programming serves to be an equalizer or perpetuator of inequality in the U.S. may depend on how fast minority groups can participate and get a “piece of the pie,” so to speak, before the available opportunities shrink.

      The bad news is that it’s looking like underrepresented groups will still have to try twice as hard for a shot at the same jobs, which is truly unfair.

      The good news is that people are more aware than ever before that the diversity gap in tech is a real problem. Ultimately, the U.S. education system will adapt, nonprofits will grow, and more female and minority students will find — and stay in — careers in computing-related tasks.

      After all, diverse teams are the only way companies will keep up with the changing demands of a world where computers are not going away.



      Source link