Categories
React Tips

React Tips — Hooks Equivalents to Class Lifecycle Methods, Dynamic Tags

React is a popular library for creating web apps and mobile apps.

In this article, we’ll look at some tips for writing better React apps.

Reference a Local Image in React

We can reference a local image with React by loading it as a module.

For instance, we can write:

<img src={require('./pic.jpeg')} />

or:

import pic from './pic.jpeg';

//...

`<img src={`pic`} />`

or:

const pic = require('./pic.jpeg');

//...

<img src={pic} />

Images can be loaded as modules with Webpack.

Scroll to the Top of the Page After Render

We can scroll to the top of the page after render by writing;

componentDidMount() {
  window.scrollTo(0, 0)
}

in a class component.

componentDidMount runs code when the component mounts.

window.scrollTo(0, 0) scrolls to the top of the page.

In a function component, we can write:

useEffect(() => {
  window.scrollTo(0, 0)
}, [])

to scroll to the top of the page.

useEffect with an empty array as the 2nd argument only runs when the component is mounted.

Why are Fragments in React Better than Container divs?

Fragments are a bit faster and has less memory usage since no extra DOM node is created.

Some CSS features like flexbox and grid have their own special parent-child relationship, so add a wrapper div will interfere with those layouts.

And less DOM elements means that there’re fewer elements to inspect.

We can make our code cleaner with:

render() {
  return (
    <>
      foo.
      <h2>A heading</h2>
      bar.
      <h2>heading</h2>
      baz.
    </>
  );
}

or:

render() {
  return (
    <React.Fragment>
      foo.
      <h2>A heading</h2>
      bar.
      <h2>heading</h2>
      baz.
    </React.Fragment>
  );
}

If we need to add the key prop, then we’ve to use the long-form.

Set Default Checked Value in Checkbox with React

We can set the default checked value in a checkbox with React by using the checked attribute.

For instance, we can write:

function Checkbox() {
  const [checked, setChecked] = React.useState(true);

  return (
    <label>
      <input type="checkbox"
        checked={checked}
        onChange={() => setChecked(!checked)}
      />
      check me
    </label>
  );
}

We called the useState hook with to set the initial value of the checked state.

And we use the setChecked function to set the checked state as we get the checked value.

onChange runs every time we check or uncheck a button, so we can pass a callback to that set the latest checked state.

With class components, we write:

class Checkbox extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      checked: true,
    };
  }
  toggleChange = () => {
    this.setState({
      checked: !this.state.checked,
    });
  }
  render() {
    return (
      <label>
        <input type="checkbox"
          checked={this.state.checked}
          onChange={this.toggleChange}
        />
        check me
      </label>
    );
  }
}

We have a checkbox that also have the checked and onChange props set.

However, in the toggleChange method, we called setState to update the state instead of calling a state change function.

Use componentDidMount() in React Hooks

If we use React hooks, then we can’t use any of the component lifecycle hooks that are in class components.

Instead, we’ve to find their hooks equivalent.

The hooks equivalent of componentDidMount is the useEffect hook with an empty array as its 2nd argument.

For instance, instead of writing:

componentDidMount() {
  window.addEventListener('click', () => {})
}

componentWillUnmount() {
  window.removeEventListener('click', () => {})
}

in a class component.

We write:

useEffect(() => {
  window.addEventListener('click', () => {});

  return () => {
    window.removeEventListener('click', () => {})
  }
}, [])

componentDidMount is equivalent to the useEffect hook with an empty array.

And componentWillUnmount is equivalent to the callback we return in the useEffect callback.

Dynamic Tag Name in JSX and React

If we want to create an element with a dynamic tag name with React, we can use the React.createElement method.

For instance, we can write:

React.createElement(`h${this.props.level}`, null, 'Hello')

In a component, we can write:

import React from 'react';

function Heading({ level, children, ...props }) {
  return React.createElement(`h${level}`, null, children)
}

Heading.defaultProps = {
  level: '1',
};

We pass in the level prop to set the type of heading.

children has the content.

Then we can use it by writing:

<Heading level="1">foo bar</Heading>

Conclusion

We can use createElement to create elements with dynamic tags.

Also, we can reference local images with React.

Fragments are better than wrapper divs since they don’t render any extra elements.

There are hooks equivalents of class component lifecycle methods.

Categories
React Tips

React Tips — Bootstrap, APIs, and Remove Array Items

React is a popular library for creating web apps and mobile apps.

In this article, we’ll look at some tips for writing better React apps.

Right Way to do an API Call in React

We can call an API within a method in a class component.

For instance, we can write:

class UserList extends React.Component {
  constructor(props) {
    super(props);
    this.state = { results: []};
  }

  componentDidMount() {
    this.getUserList();
  }

  getUserList() {
    fetch('https://randomuser.me/api/')
       .then(res => res.json());
       .then(({ results }) => this.setState({ results }));
  }

  render() {
    const persons = this.state.results.map((item, i) => (
      <div>
        <h1>{item.name.first}</h1>
        <span>{item.email}</span>
      </div>
    ));

    return (
      <div>
        <div>{persons}</div>
      </div>
    );
  }
}

We get the data in the getUserList method.

We used the Fetch API to get the data.

The results array is populated with the setState method in the last then callback.

To make it load when the component mounts, we call getUserList in the componentDidMount method.

In the render method, we map the state with by calling this.state.results.map .

And then we render the resulting list in the return statement.

We can also fetch data in a function component.

For instance, we can write:

const App= () => {
  const [users, setUsers] = React.useState([]);

  React.useEffect(() => {
    const fetchData = async () => {
      const res = await fetch('https://randomuser.me/api/')
      const { results } = await res.json();
      setUsers(results)
    }
    fetchData();
  }, []);

  return (
    <div>
      {results.map(r =>
        <div key={r.id}>{r.first.name}</div>
      )}
    </div>
  );
}

We put the API request code in the useEffect callback.

The empty array in the 2nd argument makes the callback load on mount only.

We call setUsers to set the users state.

Then we can map to components that are displayed.

The Correct Path for img on React

We always use relative paths for images.

For instance, we can write:

<img src={require('../logo.png')} alt="logo" />

or:

import logo from './logo.png';
img.src = logo;

In both examples, we import the image as a module and use them.

Include Bootstrap CSS and JavaScript in a React App

To include Bootstrap CSS and JavaScript in our app, we install the Bootstrap package.

To install it, we run:

npm install --save bootstrap@latest

Then we can import the CSS by writing:

import '../node_modules/bootstrap/dist/css/bootstrap.min.css';

or:

import 'bootstrap/dist/css/bootstrap.min.css';

To import the JavaScript files, we install jQuery and Popper along with Bootstrap by running:

npm install bootstrap jquery popper.js --save

Then we can import both the CSS and JavaScript by writing:

import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap/dist/js/bootstrap.js';

Return Empty Content in React render Function

There are many ways to return nothin in a React render function.

We can write any of the following:

<div />

<div></div>

<div>{false}</div>

<div>{null}</div>

<div>{undefined}</div>

<div>{true}</div>

with the return keyword.

We must write it out explicitly.

So we can write:

return <div />

in the render method or use return with any of the other expressions.

Removing Element from an Array in Component State

We can remove an element from an array in a component state by returning a new array without the value that we want to remove.

For instance, we can write:

removeItem(index) {
  this.setState({
    data: this.state.data.filter((_, i) => i !== index)
  });
}

within our class component.

We called filter to return an array that has the items except for the one with the given index .

And we called setState to set that as the new value of the data state.

To make sure that the new array is always derived from the current array, we can write:

removeItem(index) {
  this.setState((prevState) => ({
    data: prevState.data.filter((_, i) => i !== index)
  }));
}

We passed in a callback to setState instead and returned the same array as the previous example with the filter method.

The only difference is that the value is derived from the current value which is stored in prevState.data .

We can also use the spread operator and slice to do the same thing:

removeItem(index) {
  this.setState((prevState) => ({
    data: [...prevState.data.slice(0, index), ...prevState.data.slice(index + 1)]
  }))
}

We called slice to get the chunks of the array that we want to keep.

Then we spread them chunks with the spread operator.

Conclusion

We can call APIs in several ways within a React component.

Also, we can remove an element from an array state in several ways.

Bootstrap CSS and JavaScript can be included in a React app.

Categories
React Tips

React Tips — this, Merging States, and Mock Functions in Tests

React is a popular library for creating web apps and mobile apps.

In this article, we’ll look at some tips for writing better React apps.

Merging States with setState Instead of Overwriting

We can merge states with setState instead of overwriting if we pass in a callback to the method instead of an object.

For instance, instead of writing:

this.setState({ x: 1 });

We write:

this.setState((prevState, props) => ({
  point: {
    ...prevState.point,
    y: 1
  },
));

We pass in a callback that gets the previous state as the first parameter.

Then we merge in the previous state’s value into the returned object.

And we add y after it.

How to Change a Jest Mock Function Return Value in Each Test

We can change the mock function implementation by creating the mock function with jest.fn() .

Then we can the mockImplementation method by passing in a callback that returns the value we want.

Or we can pass the return value as the argument.

For instance, we can write:

import { foo, bar } from './module';

jest.mock('./module', () => ({
  foo: jest.fn(),
  bar: jest.fn()
}));

We mock the module’s methods with jest.fn() .

Then we call mockImplementation on it by writing:

foo.mockImplementation(() => true)

or:

foo.mockImplementation(true)

in our tests.

In a different test, we can write:

foo.mockImplementation(() => false)

or:

foo.mockImplementation(false)

There’s also the mockReturnValueOnce method that we can use.

For instance, we can write:

import { foo, bar } from './module';

jest.mock('./module', () => ({
  foo: jest.fn(),
  bar: jest.fn()
}));

describe('test suite', () => {
  it('some test', () => {
    foo.mockReturnValueOnce(true);
    bar.mockReturnValueOnce(false);
  });
});

Replace img src on Error in React

We can add an error handler to our img element to load another image on error.

For instance, we can write:

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class Image extends Component {
  constructor(props) {
    super(props);

    this.state = {
      src: props.src
    };
  }

  onError = () => {
    this.setState({
      src: this.props.fallbackSrc,
    });
  }

  render() {
    const { src } = this.state;

    return (
      <img
        src={src}
        onError={this.onError}
        {...props}
      />
    );
  }
}

Image.propTypes = {
  src: PropTypes.string,
  fallbackSrc: PropTypes.string,
};

We replace the src state with the fallbackSrc in our error handler.

This way, when the image with the given src string can’t load, then we set it to the fallbackSrc value as the value of img’s src attribute’s value.

Creating an “If” Component with React

We can use boolean expressions to create a component that displays something conditionally.

For instance, we can write:

<div>
  {(cond
    ? <div>It's true</div>
    : <div>It's false</div>
  )}
</div>

If cond is true , then <div>It’s true</div> is shown.

Otherwise, <div>It’s false</div> is shown.

We can also have null or false as an empty component that doesn’t render anything.

For instance, we can write:

<div>
  {showChild ? <Child /> : false}
</div>

If showChild is true , we show the Child component.

Otherwise, we show nothing.

We can also use an if statement bu writing:

renderPerson() {
  const personName = '';
  if (personName) {
    return <div>{personName}</div>;
  }
}

We show personName if it exists.

Then in render , we write:

render() {
  return (
    <div>
      {this.renderPerson()}
    </div>
  );
}

We render the personName if it exists.

Also, we can write:

{cond && (<div>It's true</div>)}

Passing Object as Props to JSX

To pass an object as props with JSX, we can use the spread operator.

For instance, we can write:

<Child  {...commonProps} />

where commonProps is an object.

The all the keys are passed in as props.

And all the values are passed in as the props’ values.

Fix React this.state is Undefined

If we’re using this.state in our class methods, then we should call bind to set the class as the value of this inside the method.

For instance, we can write:

<Form onClick={this.onClick.bind(this)}/>

Then the this value inside the this.onClick method would be set to the class since this is the class.

Putting this.onClick.bind(this) into the prop will create a new function on every render, so we should put it in the constructor to avoid that:

constructor(props) {
  super(props);
  this.state = {
    users: null
  }
  this.onClick = this.onClick.bind(this);
}

Conclusion

We can mock Jest methods’ return value with a few methods.

Also, we can merge states instead of overwriting them.

We can conditionally render items.

And we’ve to call bind to set this to the class.

Categories
React Tips

React Tips — Back Button, Stop Event Bubbling, Merging States

React is a popular library for creating web apps and mobile apps.

In this article, we’ll look at some tips for writing better React apps.

Prevent Event Trigger on Parent From Child

We can prevent an event from bubbling from child to parent by calling the stopPropagation method.

For instance, we can write:

class App extends Component {
  constructor(){
    super();
  }

  handleParentClick(e) {
    console.log('parent clicked');
  },

  handleChildClick(e) {
    e.stopPropagation();
    console.log('child clicked');
  },

  render() {
    return (
      <div>
        <p onClick={this.handleParentClick}>
          <span onClick={this.handleChildClick}>Click</span>
        </p>
      </div>
    );
  }
}

We created a component that has a parent and child element.

The span has the handleChildClick handler attached to it.

Since we called e.stopPropagation , we won’t get the child’s event bubbling to the parent.

We also have a handleParentClick handler that’s attached to the p element.

Download a File in React

We can create a file download link in a few ways.

One way is to use the React Router’s Link component by writing:

<Link to="/files/file.pdf" target="_blank" download>Download</Link>

We can also create a link and click on it to trigger the download.

For instance, we can write:

const link = document.createElement('a');
link.href = `file.pdf`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);

We can also use an anchor tag by writing:

<a href={uploadedFileLink} target="_blank" rel="noopener noreferrer">
   download file
</a>

We have the rel=”noopener noreferrer” attribute so that we can prevent security issues with cross-origin destinations.

This attribute will prevent outside domains from accessing the current website.

Intercept or Handle the Browser’s Back Button in React Router

We can listen to back button actions by running the setRouteLeaveHook event for back button actions.

For instance, we can write:

import {Component} from 'react';
import {withRouter} from 'react-router';

class App extends Component {
  componentDidMount() {
    this.props.router.setRouteLeaveHook(this.props.route, this.onLeave);
  }

  onLeave(nextState) {
    if (nextState.action === 'POP') {
      //...
    }
  }

  //...
}

export default withRouter(App);

We call withRouter to inject the router object, which has the setRouteLeaveHook method to let us listen for changes to this.props.route .

Then we created our own onLeave methods which we pass in as the 2nd argument.

It takes the nextState object which has the action which we can check for.

If it’s 'POP' , then the back button is pressed.

With a function component, we can listen to the history object for changes.

history has the action property which returns the action that’s being done.

If it’s 'POP' , then we know that the user pressed the back button.

For instance, we can write;

import { useHistory } from 'react-router-dom'

const App = () => {
  const { history } = useRouter();

  useEffect(() => {
    return () => {
      if (history.action === "POP") {
        //...
      }
    };
  }, [history])

  //...
}

We put it in the function we return in the useEffect callback so that we can check when the component is being unmounted.

There’s also the history.listen method that lets us listen for changes to the history.

For instance, we can write:

import { useHistory } from 'react-router-dom'

const App = () => {
  const history = useHistory();

  useEffect(() => {
    return history.listen(location => {
      if (history.action === 'POP') {
        //...
      }
    })
  }, [])

  //...
}

We can listen to the 'POP' action as we do in the previous examples.

Updating and Merging State Object Using React useState() Hook

To update and merge state objects with useState , we can pass in a callback to the state change function.

It takes the value of the previous stage as the parameter and returns the new state value that we want.

For instance, we can write:

setState(prevState => {
  return { ...prevState, ...newValues };
});

We used the spread operator to spread all the properties from the new and old state objects.

Also, we can use Object.assign to do the same thing.

For example, we can write:

setState(prevState => {
  return Object.assign({}, prevState, newValues);
});

which does the same thing.

Or we can just merge it in if we don’t really care about the current state value.

We can just write:

setState({
  ...state,
  foo: 'bar'
});

There are no guarantees about state ‘s value.

Conclusion

There are many ways to merge old states with new states.

We can call stopPropagation to stop propagation events.

There are many ways to watch for back button presses.

Categories
React Tips

React Tips — Scroll to Element, Load Fonts, Run setState in Sequence

In this article, we’ll look at some tips for writing better React apps.

Access Component Methods from the Outside in React

We can access component methods from the outside if we assign a ref to the component.

For instance, we class components, we can write:

const ref = React.createRef()

const parent = (<div>
  <Child ref={ref} />
  <button onClick={e => console.log(ref.current)}>click me</button>
</div>)

We create the ref with the React.createRef method.

Then we pass the ref to the Child component.

Then we can get the component with the ref.current property as we did in the onClick callback.

Scroll to an Element in a React Component

We can scroll to an element within a React component by using the window.scrollTo method with a ref.

For instance, in function components, we can write:

import React, { useRef } from 'react'

const scrollToRef = (ref) => window.scrollTo(0, ref.current.offsetTop);

const App = () => {
  const myRef = useRef(null)
  const scrollTo = () => scrollToRef(myRef)
  return (
    <>
      <div ref={myRef}>scroll to me</div>
      <button onClick={scrollTo}>click me to scroll</button>
    </>
  )
}

We create the scrollToRef function to call scrollTo .

We want to scroll to the top of the element, so get ref.current.offsetTop to get that and use that as the 2nd argument.

Then in App , we called the useRef hook to create our ref.

Then we can pass our ref to the div to assign it.

Once we did that, we add the scrollTo method to scroll to the div which is assigned to our ref.

With class components we can do the same thing.

For instance, we can write:

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

  render() {
    return <div ref={this.myRef}></div>
  }

  scrollToRef = () => window.scrollTo(0, this.myRef.current.offsetTop)
}

We create our ref with React.createRef and then scroll to it with the scrollToRef method.

We get the element with the current property.

The scrolling logic is the same.

If we use a ref callback to assign our ref, then we can write:

class App extends Component {

  render() {
    return <div ref={(ref) => this.myRef = ref}></div>
  }

  scrollToMyRef = () => window.scrollTo(0, this.myRef.offsetTop)
}

We pass in a callback to the ref prop instead of using createRef to create our ref.

Then we get the element that’s assigned to the ref without the current property.

Run a Function After setState is Finished Updating

We can run a function after setState finishes updating by passing in a callback into the 2nd argument of setState .

For instance, we can write:

const promiseState = async state => new Promise(resolve => this.setState(state, resolve));

We created a promise with a async function that has resolve as the 2nd argument.

Then we can write:

promiseState({...})
  .then(() => promiseState({
    //...
  })
  .then(() => {
    //...
    return promiseState({
      //...
    });
  })
  .then(() => {
    //...
  });

Then we can call setState as many times as we want.

Add Fonts to create-react-app Based Projects

To add fonts to a create-react-app project, we can put it into the CSS code.

For instance, we can write:

@font-face {
  font-family: 'SomeFont';
  src: local('SomeFont'), url(./fonts/SomeFont.woff) format('woff');
}

in index.css .

Then we can import it by writing:

import './index.css';

We defined a new font with the font-face rule.

src has the location of the font.

font-family has the font name.

We can import CSS like a module with Webpack.

We can also put fonts in index.html .

For instance, we can write:

<link href="https://fonts.googleapis.com/css?family=Montserrat" rel="stylesheet">

or write:

<style>
    @import url('https://fonts.googleapis.com/css?family=Montserrat');
</style>

Another solution is to use the webfontloader package.

To install it, we run:

yarn add webfontloader

or

npm install webfontloader --save

Then we can write:

import WebFont from 'webfontloader';

WebFont.load({
   google: {
     families: ['Open Sans:300,400,700', 'sans-serif']
   }
});

to load the font we want.

Conclusion

There are various ways to load fonts into our create-react-app project.

We can access component methods from outside a component by assigning a ref to it and then we can call the methods.

This applies to class components.

There are various ways to scroll to an element.

We can run setState in sequence if we pass in a function into the 2nd argument of it.