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.

Categories
React Tips

React Tips — React and Redux, Navigation, Drop Down Values

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

Setting State When a Drop Down Value is Changed

We can set the selected value from the dropdown as a state value by setting the key dynamically and the value to the event.target.value .

For instance, we can write:

class App extends React.Component {

  constructor(props) {
    super(props);
    this.state = { fruit: '' };
  }

  handleChange = (event) => {
    this.setState({ [event.target.name]: event.target.value });
  }

  render() {
    return (
      <select value={this,state.fruit} name='fruit' `handleChange={this.handleChange}`>
        <option value="apple">Apple</option>
        <option value="banana">Banana</option>
        <option value="cranberry">Cranberry</option>
      </select>
    )
  }

}

We set the fruit state to the selected value with the handleChange method.

It just calls setState to set the fruit state with the value, which is stored in event.target.value .

Update Nested State Properties in React

We can set nested state properties with setState .

It takes a callback with the previous state, then we return an object with the new state.

For instance, we can write:

this.setState(state=> ({ ...this.state.someProp, flag: false} }));

Or we can write:

this.setState({ someProperty: { ...this.state.someProperty, flag: false} });

to update the state without the callback.

In either example, we merge the new value to the old object with the spread operator.

Get First N Number of Elements from an Array

We can get the first N number of elements from an array with the slice method.

For instance, we can write:

const size = 5;
const items = list.slice(0, size).map(i => {
  return <Foo item={i} key={i.id} />
}

return (
  <div>
    {items}
  </div>
)

inside the render method or the function component.

We get the first 5 items with the slice method.

Then we use map to return the list of items to render.

And then we can put that anywhere.

Push to History in React Router

We can use the this.props.history.push method of React Router if we use it with a class component.

For instance, we can write:

import React from "react";
import { withRouter } from "react-router-dom";

class Foo extends React.Component {
  //...
  go() {
    this.props.history.push("/some/path");
  }
  //...
}
export default withRouter(Foo);

We have the go method inside our React component to call this.prop.history.push with the path we want to go to.

It’s available because we called the withRouter higher-order component to add the method.

With the hooks version of React Router, we can write:

import { useHistory } from "react-router-dom";

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

  const goHome = () => {
    history.push("/home");
  }

  return (
    <button type="button" onClick={goHome}>
      Go home
    </button>
  );
}

We use the useHistory hook to get the history object and we call push on it to go to the path we want.

React Redux mapDispatchToProps

With React Redux, we use the mapDispatchToProps method to map dispatch actions to props.

For instance, we can write:

class App extends Component {
  sendAlert(){
    this.props.sendAlert()
  }

  render() {
    <div>
      <h1>alert: {this.props.alert}</h1>
      <Button onClick={sendAlert}/>
    </div>
  }
}

function mapDispatchToProps(dispatch) {
  return({
    sendAlert: () => {dispatch(ALERT_ACTION)}
  })
}

function mapStateToProps(state) {
  return { alert: state.alert }
}

export const FancyButtonContainer = connect(
  mapStateToProps, mapDispatchToProps)(
  App
)

We have the this.propss.sendAlert method, which is the one that’s returned with nmapDispatchToProps .

mapDispatchToProps is a function that we can use with the connect higher-order component to map the dispatch action to props.

Likewise, mapStateToProps lets us return the state from the Redux store and make it available as a prop in our component.

So this.props.alert is the value of the alert property in the returned object.

Update the Parent’s State

We can update the parent;’s state by passing in a function from the parent to the child as a prop.

Then in the child component, we can call it to update the state.

For instance, we can write:

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.handler = this.handler.bind(this);
  }

  handler() {
    this.setState({
      foo: 'bar'
    })
  }

  render() {
    return <Child handler = {this.handler} />
  }
}

class Child extends React.Component {
  render() {
    return <button onClick={this.props.handler}>click me</button>
  }
}

We pass the this.handler method to the Child component.

We’ve to remember to call bind with this on it so the value of this will be the parent.

Then we can call it in the Child by passing it into the onClick prop as this.props.handler .

Conclusion

We can pass functions from the parent component to the child.

We can set the state when the dropdown is changed.

There are a few ways to navigate with React Router.

Redux can be used to map actions and states to props of a component.