Categories
JavaScript Vue

Add Simple State Management with Vuex

Vue.js is an easy to use web app framework that we can use to develop interactive front end apps.

With Vuex, we can store our Vue app’s state in a central location.

In this article, we’ll look at how to add Vuex to our app and add a simple store.

What is Vuex?

Vuex is for storing states that are needed by multiple components in one central location.

https://thewebdev.info/wp-content/uploads/2020/06/vuex.png

It lets us get and set shared state and propagate any changes made to the shared state automatically to all components.

In the workflow diagram above, we can see that Vuex mutations are committed by our code when we get something from the back end API.

The mutation will update the state with the back end API data and the state will be updated in our Vue components.

We can also dispatch mutations from Vue components to change the Vuex store state the change will be propagated to all components that have access to the store.

Getting Started

We can include Vuex with a script tag in our HTML code:

<script src="https://unpkg.com/vuex"></script>

Then we can create a simple store by using the Vuex.Store as follows:

const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state) {  
      state.count++;  
    }  
  }  
});

The code above is a store which stores the state count .

Then we can commit the increase mutation by running:

store.commit("increase");

Then we can get the state after the mutation is done by running:

console.log(store.state.count);

store.state.count is the count state from the Vuex store. Then we should see 1 logged.

Getting Vuex State into Vue Components

We can get the state into our store by adding a computed property.

Therefore, to add the state into our store, we can write the following:

index.js :

const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state) {  
      state.count++;  
    }  
  }  
});

new Vue({  
  el: "#app",  
  computed: {  
    count() {  
      return store.state.count;  
    }  
  }  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vuex"></script>  
  </head>  
  <body>  
    <div id="app">  
      <p>{{count}}</p>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>

Then we should see 0 displayed since count is 0 initially in the store .

Then whenever store.state.count updates, the computed property will be updated and the view will update with the new value.

A more convenient way to inject the store into all child components is to add the store in the root component as follows:

index.js :

const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state) {  
      state.count++;  
    }  
  }  
});

new Vue({  
  el: "#app",  
  store  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vuex"></script>  
  </head>  
  <body>  
    <div id="app">  
      <p>{{$store.state.count}}</p>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>

Then it’ll be available to all child components and we don’t have to worry about add computed properties for every value.

It works with child component without much changes:

const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state) {  
      state.count++;  
    }  
  }  
});

Vue.component("counter", {  
  template: `<div>{{ count }}</div>`,  
  computed: {  
    count() {  
      return this.$store.state.count;  
    }  
  }  
});

new Vue({  
  el: "#app",  
  store  
});

this.$store is available to the counter component just by including it in the root Vue component.

The mapState Helper

To avoid adding a new computed property for every state that’s in the store, we can use the mapState helper to add it. For example, we can write the following code to do that:

index.js :

const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state) {  
      state.count++;  
    }  
  }  
});

Vue.component("counter", {  
  data() {  
    return {  
      localCount: 1  
    };  
  },  
  template: `  
    <div>  
      <div>{{ count }}</div>  
      <div>{{ countAlias }}</div>  
      <div>{{ countPlusLocal }}</div>  
    </div>  
  `,  
  computed: Vuex.mapState({  
    count: state => state.count,  
    countAlias: "count",  
    countPlusLocal(state) {  
      return state.count + this.localCount;  
    }  
  })  
});

new Vue({  
  el: "#app",  
  store  
});

index.html :

<!DOCTYPE html>  
<html>  
  <head>  
    <title>App</title>  
    <meta charset="UTF-8" />  
    <script src="https://unpkg.com/vue/dist/vue.js"></script>  
    <script src="https://unpkg.com/vuex"></script>  
  </head>  
  <body>  
    <div id="app">  
      <counter></counter>  
    </div>  
    <script src="index.js"></script>  
  </body>  
</html>

Then we see:

001

Because we called mapState as follows:

computed: Vuex.mapState({  
  count: state => state.count,  
  countAlias: "count",  
  countPlusLocal(state) {  
    return state.count + this.localCount;  
  }  
})

We have:

count: state => state.count,

which gets the count state from the store and returns it. The count is 0 so we get 0.

Then we have:

countAlias: "count"

which is a shorthand for:

count: state => state.count

And finally, we have:

countPlusLocal(state) {  
  return state.count + this.localCount;  
}

which adds state.count from the store to this.localCount , which we set to 1.

Object Spread Operator

We can combine local computed properties with mapState by applying the spread operator to mapState as follows:

index.js :

const store = new Vuex.Store({  
  state: {  
    count: 0  
  },  
  mutations: {  
    increase(state) {  
      state.count++;  
    }  
  }  
});

Vue.component("counter", {  
  data() {  
    return {  
      localCount: 1  
    };  
  },  
  template: `  
    <div>  
      <div>{{ count }}</div>  
      <div>{{ foo }}</div>        
    </div>  
  `,  
  computed: {  
    foo() {  
      return 2;  
    },  
    ...Vuex.mapState({  
      count: "count"  
    })  
  }  
});

new Vue({  
  el: "#app",  
  store  
});

Then we get:

02

displayed since foo always returns 2.

Components Can Still Have Local State

Components can still have their own local state, so we don’t have to put everything in the Vuex store.

Conclusion

We can add a Vuex store to our app to store the states of our app that are shared by multiple components.

To make getting state easy, we can include the store in the root Vue component.

Then we call the mapState helper to get the states we want in any component.

We can also combine it with the local states with the spread operator in the computed object.

Categories
JavaScript Mega-Guides React

React Basics Mega-Guide

React is a library for creating front end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

In this article, we’ll look at how to create simple apps with React.

Getting Started

The easiest way to create a React app is to use the Create React App Node package.

We can run it by running:

npx create-react-app my-app

Then we can go to the my-app and run the app by running:

cd my-app  
npm start

Create React App is useful for creating a single-page app.

React apps don’t handle any backend logic or databases.

We can use npm run build to build the app to create the built app for production.

Creating Our First React App

Once we ran Create React App as we did above, we can create our first app. To create it, we go into App.js and then start changing the code there.

To make writing our app easy, we’ll use JSX to do it. It’s a language that resembles HTML, but it’s actually just syntactic sugar on top of JavaScript.

Therefore, we’ll use the usual JavaScript constructs in JSX.

We’ll start by creating a Hello World app. To do this, we replace what’s there with the following in index.js:

import React from "react";  
import ReactDOM from "react-dom";

function App() {  
  return (  
    <div>  
      <h1>Hello World</h1>  
    </div>  
  );  
}

const rootElement = document.getElementById("root");  
ReactDOM.render(<App />, rootElement);

In the code above, we have the App component, which is just a function. It returns:

<div>  
  <h1>Hello World</h1>  
</div>

which is our JSX code to display Hello World. h1 is a heading and div is a div element.

The code above looks like HTML, but it’s actually JSX.

What we have above is a function-based component since the component is written as a function.

In the last 2 lines, we get the element with ID root from public/index.html and put our App component inside it.

Another way to write the code above is to write:

import React from "react";  
import ReactDOM from "react-dom";

class App extends React.Component {  
  render() {  
    return (  
      <div>  
        <h1>Hello World</h1>  
      </div>  
    );  
  }  
}

const rootElement = document.getElementById("root");  
ReactDOM.render(<App />, rootElement);

The code above is a class-based component, which has a render method to render the same JSX code into HTML.

The difference between the 2 examples is that one is a function and the other is a class that extends React.Component .

Otherwise, they’re the same. Any component file has to include:

import React from "react";  
import ReactDOM from "react-dom";

Otherwise, we’ll get an error.

React doesn’t require JSX, it’s just much more convenient to use it. A third way to create a Hello World app is to use the React.createElement method.

We can use the method as follows:

import React from "react";  
import ReactDOM from "react-dom";

const e = React.createElement;  
const App = e("h1", {}, "Hello World");

const rootElement = document.getElementById("root");  
ReactDOM.render(App, rootElement);

The first argument of the createElement method is the tag name as a string, the second argument has the props, which are objects that we pass to the component created, and the third argument is the inner text of them element.

We won’t be using this very often since it’ll get very complex if we have to nest components and adding interaction.

Embedding Expressions in JSX

We can embed JavaScript expressions between curly braces. For example, we can write:

import React from "react";  
import ReactDOM from "react-dom";  
function App() {  
  const greeting = "Hello World";  
  return (  
    <div>  
      <h1>{greeting}</h1>  
    </div>  
  );  
}  
const rootElement = document.getElementById("root");  
ReactDOM.render(<App />, rootElement);

Then we see Hello World on the screen again.

Something more useful world calling a function as follows:

import React from "react";  
import ReactDOM from "react-dom";  
function App() {  
  const formatName = user => {  
    return `${user.firstName} ${user.lastName}`;  
  }; 

  const user = {  
    firstName: "Jane",  
    lastName: "Smith"  
  }; 

  return (  
    <div>  
      <h1>{formatName(user)}</h1>  
    </div>  
  );  
}  
const rootElement = document.getElementById("root");  
ReactDOM.render(<App />, rootElement);

In the code above, we defined a formatName function inside the App component that takes a user object and returns user.firstName and user.lastName joined together.

Then we defined a user object with those properties and called the function inside the curly braces.

Whatever’s return will be displayed between the braces. In this case, it’ll be Jane Smith.

Lifting State Up

We should lift any shared state up to their closest common ancestor.

This way, one state can be shared between multiple child components by passing them down via props.

For example, if we want to build a calculator for converting lengths, we can write the following:

import React from "react";  
import ReactDOM from "react-dom";

class LengthInput extends React.Component {  
  constructor(props) {  
    super(props);  
    const { length } = this.props;  
    this.state = { length };  
  }  
  
  handleChange(e) {  
    this.props.onChange(e);  
  } 

  componentWillReceiveProps(props) {  
    const { length } = props;  
    this.setState({ length });  
  } 

  render() {  
    const { unit } = this.props;  
    return (  
      <>  
        <label>Length ({unit})</label>  
        <input  
          value={this.state.length}  
          onChange={this.handleChange.bind(this)}  
          placeholder={this.props.unit}  
        />  
        <br />  
      </>  
    );  
  }  
}

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = { lengthInMeter: 0, lengthInFeet: 0 };  
  } 

  handleMeterChange(e) {  
    this.setState({ lengthInMeter: +e.target.value });  
    this.setState({ lengthInFeet: +e.target.value \* 3.28 });  
  } 

  handleFeetChange(e) {  
    this.setState({ lengthInFeet: +e.target.value });  
    this.setState({ lengthInMeter: +e.target.value / 3.28 });  
  } 

  render() {  
    return (  
      <div className="App">  
        <LengthInput  
          length={this.state.lengthInMeter}  
          onChange={this.handleMeterChange.bind(this)}  
          unit="meter"  
        />  
        <LengthInput  
          length={this.state.lengthInFeet}  
          onChange={this.handleFeetChange.bind(this)}  
          unit="feet"  
        />  
      </div>  
    );  
  }  
}

const rootElement = document.getElementById("root");  
ReactDOM.render(<App />, rootElement);

In the code above, we have a length converter than converts meters to feet when we’re typing in the meters field and vice versa.

What we’re doing is that we keep the lengths all in the App component. This is why the principle is called lifting the states up.

Since we’re keeping the lengths in the App component, we have to pass them down to the LengthInput components.

To do that, we pass props to them. Also, we pass in the units, and the change handler functions down to our LengthInput components, so that they can the functions to update the states in the App component.

In the handleFeetChange and handleMeterChange functions, we set the state according to the values entered in the LengthInput components.

We call this.setState in both functions to set the states. Each time setState is called, render will be called, so that the latest state will be passed down to our LengthInput components.

In the LengthInput components, we have the componentWillReceiveProps hook which will get the latest prop values and then set the length state accordingly.

this.state.length is set as the value of the input elements in LengthInput , so the inputted value will be shown.

The advantage of lifting the states up to the parent component is that we only have to keep one copy of the state. Also, we don’t have to repeat the processing of the states in different child components.

The values of the inputs stay in sync because they’re computed from the same state.

Uncontrolled Components

Uncontrolled components are where we use the DOM properties to manipulate form inputs.

We can use a ref to get form values directly from the DOM.

For example, we can write the following:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.input = React.createRef();  
  } 

  handleSubmit(event) {  
    alert(`Name submitted: ${this.input.current.value}`);  
    event.preventDefault();  
  } 

  render() {  
    return (  
      <form onSubmit={this.handleSubmit.bind(this)}>  
        <label>  
          Name:  
          <input type="text" ref={this.input} />  
        </label>  
        <input type="submit" value="Submit" />  
      </form>  
    );  
  }  
}

In the code above we created the this.input ref in the constructor and attached it to the input element.

Then when we type in something and click Submit, we get whatever we typed into the input box displayed in the alert box since we accessed it with this.input.current.value .

This makes integrating React and non-React code easier since we’re using the DOM to get the value.

Default Values

The value attribute on form elements will override the value in the DOM.

With an uncontrolled component, we often want to specify the initial value and leave subsequent updates uncontrolled.

We can set the defaultValue attribute to do this:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.input = React.createRef();  
  } 

  handleSubmit(event) {  
    alert(`Name submitted: ${this.input.current.value}`);  
    event.preventDefault();  
  } 

  render() {  
    return (  
      <form onSubmit={this.handleSubmit.bind(this)}>  
        <label>  
          Name:  
          <input type="text" defaultValue="Foo" ref={this.input} />  
        </label>  
        <input type="submit" value="Submit" />  
      </form>  
    );  
  }  
}

In the code above, we set the defaultValue attribute to Foo , which is the value of this.input.current.value if we don’t change the input value.

The file input Tag

File inputs are always uncontrolled components because its value can only be set by a user and not programmatically.

Therefore, we have to use a ref to access its value.

For example, we can write the following:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.fileRef = React.createRef();  
  } 

  handleSubmit(event) {  
    alert(`Filename: ${this.fileRef.current.files[0].name}`);  
    event.preventDefault();  
  } 

  render() {  
    return (  
      <form onSubmit={this.handleSubmit.bind(this)}>  
        <input type="file" ref={this.fileRef} />  
        <input type="submit" value="Submit" />  
      </form>  
    );  
  }  
}

In the code above, we created a ref called fileRef and attached it to the file input. Then we get the files[0].name property that has the name of the selected file.

We can use the File API to do things with the selected file.

Lists and Keys

We can transform lists into HTML by calling the array’s map method.

For example, if we want to display an array of numbers as a list, we can write:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
  } 

  render() {  
    return (  
      <div>  
        {[1, 2, 3, 4, 5].map(num => (  
          <span>{num}</span>  
        ))}  
      </div>  
    );  
  }  
}

In the code above, we called map on the [1, 2, 3, 4, 5] array. In the map method’s callback, we returned a span with the number inside and we do the same for each element.

Then we get:

12345

displayed on the screen.

We can assign it to a variable and then pass it into the ReactDOM.render method as follows:

import React from "react";  
import ReactDOM from "react-dom";
const nums = [1, 2, 3, 4, 5].map(num => <span>{num}</span>);
const rootElement = document.getElementById("root");  
ReactDOM.render(nums, rootElement);

We’ll get the same items displayed.

Also, we can use the same code inside the render method:

import React from "react";  
import ReactDOM from "react-dom";

class App extends React.Component {  
  constructor(props) {  
    super(props);  
  } 

  render() {  
    const nums = [1, 2, 3, 4, 5].map(num => <span>{num}</span>);  
    return <div>{nums}</div>;  
  }  
}

const rootElement = document.getElementById("root");  
ReactDOM.render(<App />, rootElement);

Keys

When we render lists, we should provide a value for key prop for each rendered element so that React can identify which items have changed, added, or removed.

It gives elements a stable identity. We should pick a key by using a string that uniquely identifies a list item among its siblings.

A key should be a string value.

For example, if we want to render a list of to-do items, we should pick the id field as the key ‘s value as follows:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = {  
      todos: [  
        { id: 1, text: "eat" },  
        { id: 2, text: "drink" },  
        { id: 3, text: "sleep" }  
      ]  
    };  
  } 

  render() {  
    return (  
      <div>  
        {this.state.todos.map(todo => (  
          <p key={todo.id.toString()}>{todo.text}</p>  
        ))}  
      </div>  
    );  
  }  
}

In the code above, we have the key={todo.id.toString()} prop to set the key to the todo ‘s id converted to a string.

If we have no stable identity for our items, we can use the index for the entry as a last resort:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = {  
      todos: [{ text: "eat" }, { text: "drink" }, { text: "sleep" }]  
    };  
  } 

  render() {  
    return (  
      <div>  
        {this.state.todos.map((todo, index) => (  
          <p key={index.toString()}>{todo.text}</p>  
        ))}  
      </div>  
    );  
  }  
}

index is always available and it’s unique for each array element, so it can be used as a value for the key prop.

Extracting Components with Keys

If we render components, we should put the key prop in the component rather than the element that’s being rendered.

For example, the following is incorrectly using the key prop:

function TodoItem({ todo }) {  
  return <p key={todo.id.toString()}>{todo.text}</p>;  
}

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = {  
      todos: [  
        { id: 1, text: "eat" },  
        { id: 2, text: "drink" },  
        { id: 3, text: "sleep" }  
      ]  
    };  
  } 

  render() {  
    return (  
      <div>  
        {this.state.todos.map(todo => (  
          <TodoItem todo={todo} />  
        ))}  
      </div>  
    );  
  }  
}

In the TodoItem component, we have:

<p key={todo.id.toString()}>{todo.text}</p>;

with the key prop. We don’t want this there because we don’t need to identify a unique li since it’s isolated from the outside already. Instead, we want to identify a unique TodoItem .

Instead, we should write:

function TodoItem({ todo }) {  
  return <p>{todo.text}</p>;  
}class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = {  
      todos: [  
        { id: 1, text: "eat" },  
        { id: 2, text: "drink" },  
        { id: 3, text: "sleep" }  
      ]  
    };  
  } 

  render() {  
    return (  
      <div>  
        {this.state.todos.map(todo => (  
          <TodoItem todo={todo} key={todo.id.toString()} />  
        ))}  
      </div>  
    );  
  }  
}

We should add keys to items return with map ‘s callback.

Keys Only Need to Be Unique Among Siblings

Keys only need to be unique among sibling elements.

For example, we can write:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = {  
      posts: [  
        { id: 1, text: "eat" },  
        { id: 2, text: "drink" },  
        { id: 3, text: "sleep" }  
      ],  
      comments: [  
        { id: 1, text: "eat" },  
        { id: 2, text: "drink" },  
        { id: 3, text: "sleep" }  
      ]  
    };  
  } 

  render() {  
    return (  
      <div>  
        <div>  
          {this.state.posts.map(post => (  
            <p key={post.id.toString()}>{post.text}</p>  
          ))}  
        </div>  
        <div>  
          {this.state.comments.map(comment => (  
            <p key={comment.id.toString()}>{comment.text}</p>  
          ))}  
        </div>  
      </div>  
    );  
  }

Since posts and comments aren’t rendered in the same div , the key values can overlap.

The key prop doesn’t get passed to components. If we need the same value in a component we have to use a different name.

Embedding map() in JSX

We can embed the expression that calls map straight between the curly braces.

For example, we can write:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
  } 

  render() {  
    return (  
      <div>  
        {[1, 2, 3, 4, 5].map(num => (  
          <span key={num.toString()}>{num}</span>  
        ))}  
      </div>  
    );  
  }  
}

useState

The useState hook lets us manage the internal state of a function component. It takes an initial value as an argument and returns an array with the current state and a function to update it.

It returns the initial state when the component is initially rendered.

We can pass in a function to update the value if the new value is computed using the previous state.

For example, we can write the following to update the value based on a previous one:

function App() {  
  const [count, setCount] = React.useState(0);  
  return (  
    <>  
      Count: {count}  
      <button onClick={() => setCount(0)}>Reset</button>  
      <button onClick={() => setCount(prevCount => prevCount - 1)}>  
        Decrement  
      </button>  
      <button onClick={() => setCount(prevCount => prevCount + 1)}>  
        Increment  
      </button>  
    </>  
  );  
}

In the code above, we have:

setCount(prevCount => prevCount - 1)}

and:

setCount(prevCount => prevCount + 1)}

which decrements the count and increment it respectively by passing in functions that take the previous count as the parameter and return the new count.

Otherwise, we can just pass in the new value to the state update function as we did in:

setCount(0)

useState doesn’t automatically merge update objects. We can replicate this behavior with the spread syntax:

function App() {  
  const [nums, setNums] = React.useState({});  
  return (  
    <>  
      <p>{Object.keys(nums).join(",")}</p>  
      <button  
        onClick={() =>  
          setNums(oldNums => {  
            const randomObj = { [Math.random()]: Math.random() };  
            return { ...oldNums, ...randomObj };  
          })  
        }  
      >  
        Click Me  
      </button>  
    </>  
  );  
}

In the code above, we have:

setNums(oldNums => {  
            const randomObj = { [Math.random()]: Math.random() };  
            return { ...oldNums, ...randomObj };  
          })

to create a randomObj object with a random number as the key and value, and we merge that into another object with the old value then return it.

Then we display it with:

Object.keys(nums).join(",")

by getting the keys and joining them together.

Lazy initial state

We can pass in a function to useState if we want to delay the setting of the initial state.

It’ll be ignored after the initial render if we pass in a function.

This is useful if the initial state is computed from some expensive operation.

For example, we can write:

function App() {  
  const [count, setCount] = React.useState(() => 0);  
  return (  
    <>  
      Count: {count}  
      <button onClick={() => setCount(() => 0)}>Reset</button>  
      <button onClick={() => setCount(prevCount => prevCount - 1)}>  
        Decrement  
      </button>  
      <button onClick={() => setCount(prevCount => prevCount + 1)}>  
        Increment  
      </button>  
    </>  
  );  
}

In the code above, we have:

React.useState(() => 0)

which is a function that just returns 0.

We’ll see the same results as before.

Bailing out of a state update

If we update a state hook with the same value as the current. React will skip updating the state without rendering the children or firing effects.

React uses Object.is() to compare the current and new states, which is close to the === operator except that +0 and -0 are treated to be not equal and NaN is equal to itself.

React may still render before bailing out but it won’t go deeper into the tree if it finds that the old and new values are the same.

useEffect

We can use the useEffect hook to do various operations that aren’t allowed inside the main body of the function component, which is anything outside the rendering phase.

Therefore, we can use this to do any mutations, subscriptions, setting timers, and other side effects.

It takes a callback to run the code.

We can return a function inside to run any cleanup code after each render and also when the component unmounts.

The callback passed into useEffect fires after layout and paint, during a deferred event.

This makes this suitable for running operations that shouldn’t block the browser from updating the screen.

Code that must be run synchronously can be put into the callback of the useLayoutEffect hook instead, which is the synchronous version of useEffect .

It’s guaranteed to fire before any new renders. React will always flush the previous render’s effects before starting a new update.

Conditionally firing an effect

We can pass in a second argument to useEffect with an array of values that requires an effect to be run when they change.

For example, we can use it to get data from an API on initial render as follows:

function App() {  
  const [joke, setJoke] = React.useState({});  
  useEffect(() => {  
    (async () => {  
      const response = await fetch("https://api.icndb.com/jokes/random");  
      const res = await response.json();  
      console.log(res);  
      setJoke(res);  
    })();  
  }, []);  
  return (  
    <>  
      <p>{joke.value && joke.value.joke}</p>  
    </>  
  );  
}

Passing an empty array as the second argument will stop it from loading in subsequent renders.

We can pass in a value to the array to watch the value in the array change and then run the callback function:

function App() {  
  const [joke, setJoke] = React.useState({});  
  const [id, setId] = React.useState(1);  
  useEffect(() => {  
    (async () => {  
      const response = await fetch(`https://api.icndb.com/jokes/${id}`));  
      const res = await response.json();  
      console.log(res);  
      setJoke(res);  
    })();  
  }, [id]);  
  return (  
    <>  
      <button onClick={() => setId(Math.ceil(Math.random() * 100))}>  
        Random Joke  
      </button>  
      <p>{joke.value && joke.value.joke}</p>  
    </>  
  );  
}

In the code above, when we click the Random Joke button, setId is called with a new number between 1 and 100. Then id changes, which triggers the useEffect callback to run.

Then joke is set with a new value, then the new joke is displayed on the screen.

useContext

We can use the useContext hook to read shared data shared from a React context. It accepts the context object returned from React.createContext as an argument and returns the current context value.

The current context value is determined by the value prop of the nearest context provider.

We can use it as follows:

const ColorContext = React.createContext("green");function Button() {  
  const color = React.useContext(ColorContext);  
  return <button style={{ color }}>button</button>;  
}function App() {  
  return (  
    <>  
      <ColorContext.Provider value="blue">  
        <Button />  
      </ColorContext.Provider>  
    </>  
  );  
}

In the code above, we created a new React context with:

const ColorContext = React.createContext("green");

Then in App , we wrapped out Button with the ColorContext.Provider with the value prop set to blue .

Then in Button , we have:

const color = React.useContext(ColorContext);

to get the value passed in from the ColorContext.Provider and set it to color .

Finally, we set the color style of the button with the color ‘s value.

A component calling useContext will always re-render when the context value changes. If re-rendering is expensive, then we can optimize it with memoization.

useContext is the React hooks version of Context.Consumer .

useReducer

This hook is an alternative to useState . It accepts a reducer function of type (state, action) => newState .

useReducer is preferable to useState when we have complex state logic that involves multiple sub-values or when the next state depends on the previous one.

It also lets us optimize performance for components that trigger deep updates because we can pass dispatch down instead of callbacks.

For example, we can write:

const INCREMENT = "INCREMENT";  
const DECREMENT = "DECREMENT";function reducer(state, action) {  
  switch (action.type) {  
    case INCREMENT:  
      return { count: state.count + 1 };  
    case DECREMENT:  
      return { count: state.count - 1 };  
    default:  
      throw new Error();  
  }  
}

function App() {  
  const [state, dispatch] = React.useReducer(reducer, { count: 0 });  
  return (  
    <>  
      Count: {state.count}  
      <button onClick={() => dispatch({ type: DECREMENT })}>Decrement</button>  
      <button onClick={() => dispatch({ type: INCREMENT })}>Increment</button>  
    </>  
  );  
}

In the code above, we have our reducer which returns the new state depends on the action.type ‘s value. In this case, it’s either 'INCREMENT' or 'DECREMENT' .

If it’s ‘INCREMENT’ , we return { count: state.count + 1 } .

If it’s ‘DECREMENT’ , we return { count: state.count — 1 } .

Otherwise, we throw an error.

Then in App , we call useReducer by passing in a reducer as the first argument and the initial state as the second argument.

Then we get the state object, which has the current state object and a dispatch function, which we can call with an action object, which has the type property with the value being one of ‘INCREMENT’ or ‘DECREMENT' .

We used the dispatch function in the buttons to update the state.

Finally, we display the latest state in state.count .

Lazy initialization

We can pass in a function to the 3rd argument of useReducer to initialize the state lazily.

The initial state will be set to init(initialArg) .

For instance, we can rewrite the previous example as follows:

const init = initialCount => {  
  return { count: initialCount };  
};

const INCREMENT = "INCREMENT";  
const DECREMENT = "DECREMENT";

function reducer(state, action) {  
  switch (action.type) {  
    case INCREMENT:  
      return { count: state.count + 1 };  
    case DECREMENT:  
      return { count: state.count - 1 };  
    default:  
      throw new Error();  
  }  
}
function App() {  
  const [state, dispatch] = React.useReducer(reducer, 0, init);  
  return (  
    <>  
      Count: {state.count}  
      <button onClick={() => dispatch({ type: DECREMENT })}>Decrement</button>  
      <button onClick={() => dispatch({ type: INCREMENT })}>Increment</button>  
    </>  
  );  
}

First, we have:

const init = initialCount => {  
  return { count: initialCount };  
};

to return the initial state.

And instead of writing:

React.useReducer(reducer, { count: 0 });

We have:

React.useReducer(reducer, 0, init);

0 is passed in as the initialCount of init .

Then the rest of the code is the same as before.

Bailing out of a dispatch

If the same value is returned from a Reducer hook is the same as the current state, React will bail out without rendering the children or firing effects.

The comparison is done using the Object.is() algorithm.

If we’re doing expensive operations while rendering, we can optimize it with useMemo .

Conclusion

We can create a React app with the Create React App Node package.

Then we can add components as a function, class, or with React.createElement .

The first 2 ways are used most often since they return JSX in the function or the render method of the component class respectively.

JSX is much more convenient than createElement for writing JavaScript code with React, especially when our app gets complex.

We can embed JavaScript expressions in between curly braces.

Hooks are used to change internal state, commit side effects, or hold any other logic.

React Router lets us navigate between different pages,

The Context API lets us share data between any components.

Categories
JavaScript Vue

Using a For Loop with Vuejs

We can render lists by using a for loop with Vuejs.

The for loop equivalent in Vuejs is the v-for directive.

To use it, we can write;

<ul id="example">
  <li v-for="item in items" :key="item.name ">
    {{ item.name }}
  </li>
</ul>

and:

const example = new Vue({
  el: '#example',
  data: {
    items: [
      { name: 'Foo' },
      { name: 'Bar' }
    ]
  }
})

We have an items array with the list items to render

Then we use v-for with the items array to render them items.

We need the key prop with a unique value for each entry for Vuejs to identify the entries properly.

We can also add the index by changing our v-for for loop.

For instance, we can write:

<ul id="example">
  <li v-for="(item, index) in items">
    {{ index }} - {{ item.name }}
  </li>
</ul>

and:

const example = new Vue({
  el: '#example',
  data: {
    parentMessage: 'Parent',
    items: [
      { name: 'Foo' },
      { name: 'Bar' }
    ]
  }
})

index has the index of the array.

We can also loop through objects.

For instance, we can write:

<ul id="v-for-object">
  <li v-for="value in object">
    {{ value }}
  </li>
</ul>

and

new Vue({
  el: '#v-for-object',
  data: {
    object: {
      name: 'james'.
      age: 20,
      gender: 'male'
    }
  }
})

We loop through the keys of the object in our Vuejs app with the same for loop.

value has the property value.

We can also add the property name and index to the loop.

For instance, we can write:

<div v-for="(value, name) in object">
  {{ name }}: {{ value }}
</div>

value is the property value and name is the property name.

We can also add the index to our Vuejs for loop by writing:

<div v-for="(value, name, index) in object">
  {{ index }}. {{ name }}: {{ value }}
</div>

We can create a Vuejs for loop that display numbers by writing a number after the in instead of an array or object.

For instance, we can write:

<div>
  <span v-for="n in 100">{{ n }} </span>
</div>

We can v-for with a `template component to render multiple items.

For instance, we can write:

<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li><hr /></li>
  </template>
</ul>

to render multiple items in each iteration of the v-for Vuejs for loop.

The Vuejs equivalent of a for loop is the v-for directive.

We can use it to render objects and array entries on the screen.

Also, we can use it to loop through a range of numbers and display them.

Categories
JavaScript JavaScript Best Practices

More JavaScript Habits we can Follow

To make code easy to read and maintain, we should follow some best practices.

In this article, we’ll look at some best practices we should follow to make everyone’s lives easier.

No Reassigning Exceptions in catch clauses

We shouldn’t reassign the error object in the catch clause.

Instead, we should assign it to a new variable to ensure that we don’t lose any information.

For instance, instead of writing:

try {
  // ..
} catch (e) {
  e = 10;
}

We write:

try {
  // ...
} catch (e) {
  const foo = 10;
}

No Unnecessary Boolean Casts

If we already have a boolean variable, then e don’t need to cast it again.

For instance, instead of writing:

var foo = !!!bar;

var foo = !!bar ? baz : bat;

var foo = Boolean(!!bar);

var foo = new Boolean(!!bar);

We write:

var foo = !bar;

var foo = bar ? baz : bat;

var foo = Boolean(bar);

var foo = new Boolean(bar);

Boolean and !! already does the casting so we don’t have to do it again.

No Innecessary Parentheses

We shouldn’t have extra parentheses in our code.

For instance, instead of writing:

a = (b * c);

(a * b) + c;

We write:

a = b * c;

a * b + c;

We skip them to save some typing and make them easier to read.

No Unnecessary Semicolons

We shouldn’t have more semicolons than it’s necessary.

For example, instead of writing:

var x = 10;;

function foo() {
  // code
};

We write:

var x = 10;

function foo() {
    // code
}

No Reassigning Function Declarations

We shouldn’t reassign function declarations.

Instead, we assign whatever we want to assign to a new variable.

For instance instead of writing:

function foo() {}
foo = bar;

We write:

var foo = function () {}
foo = bar;

If we create a function, then keep it a function.

No Assignment to Imported Bindings

If we have imported bindings, then we should use it directly or as to rename it.

Otherwise, we assign what we have to a new variable and then work with it.

For instance, we write:

import mod from "./mod"

mod.prop = 1;

And not:

import mod from "./mod"

mod = 1;

No Variable or Function Declarations in Nested Blocks

We shouldn’t have function declarations in nested blocks.

It’s invalid syntax even though it’s accepted.

For instance, instead of writing:

if (test) {
    function doWork () { }
}

We write:

function doWork () { }

We can also write nested declarations:

function doSomething() {
  function doAnotherThing() {}
}

Conclusion

We shouldn’t use invalid syntax.

Also, redundant code is bad.

Extra parentheses should be removed to save us typing and space.

Categories
JavaScript JavaScript Best Practices

Removing Useless Expressions – JavaScript Best Practices

To make code easy to read and maintain, we should follow some best practices.

In this article, we’ll look at some best practices we should follow to make everyone’s lives easier.

No Constant Expressions in Conditions

We shouldn’t have constant expressions in conditions.

They either always run or never run if they’re present.

For instance, don’t write:

if (false) {
   foo();
}

Instead, write:

if (x === 1) {
   foo();
}

No Control Characters in Regex

We shouldn’t have control characters in a regex.

They are rarely used and it’s probably a mistake to check for them.

Instead of writing:

const pattern = /\x1f/;

or:

const pattern = new RegExp("\x1f");

We write:

const pattern1 = /\x20/;
const pattern2 = new RegExp("\x20");

instead.

Don’t Use debugger

debugger sets a breakpoint in our JavaScript code so we can inspect the variables.

This shouldn’t be in our production code.

So instead of writing:

const isTruthy = (x) => {
  debugger;
  return Boolean(x);
}

We write:

const isTruthy = (x) => {
  return Boolean(x);
}

No Duplicate Arguments in Function Definitions

Duplicate argument names isn’t valid syntax.

It’ll throw an error if strict mode is on.

Instead of writing:

function foo(a, b, a) {
  console.log(a);
}

We write:

function foo(a, b) {
  console.log(a);
}

No Duplicate if-else-if Conditions

We shouldn’t have duplicate conditions in our if statements.

The duplicate is useless and causes confusion.

So instead of writing:

if (isSomething(x)) {
  foo();
} else if (isSomething(x)) {
  bar();
}

We write:

if (isSomething(x)) {
  foo();
}

No Duplicate Keys in Object Literals

Duplicate keys are confusing and useless.

So we shouldn’t write:

const foo = {
   bar: "baz",
   bar: "qux"
};

Instead, we write:

const foo = {
   bar: "qux"
};

No Duplicate case Label

switch statements shouldn’t have more than one case label.

As with other duplicates, they cause confusion and are redundant.

So instead of writing:

switch (a) {
  case 1:
    break;
  case 2:
    break;
  case 1:
    break;
  default:
    break;
}

We write:

switch (a) {
  case 1:
    break;
  case 2:
    break;
  default:
    break;
}

No Empty Block Statements

Empty blocks are useless. So we should remove them.

Instead of writing:

if (foo) {
}

or

while (foo) {
}

or

switch(foo) {
}

We write:

if (foo) {
  bar();
}

or

while (foo) {
  bar();
}

or:

switch(foo) {
  case 1:
    //...
    break;
}

Conclusion

We shouldn’t have duplicates of most things.

Also, we should remove control characters from regexes and debugger.