Categories
React Tips

React Tips — Get Data, Check Scrolling, and Way Use React Router Properly

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.

‘You should not use Route or withRouter() outside a Router when using react-router 4’ Error with the styled-components Library

To fix this error, we should make sure that we wrap the BrowserRouter component around our app.

For instance, we can write:

import { BrowserRouter } from 'react-router-dom';

ReactDOM.render(
   <BrowserRouter>
     <App />
   </BrowserRouter>
, document.getElementById('root'));

Listening to Window Events from Components

We can listen to events by attach event listeners in the componentDidMount method.

Then the listener is added when the component mounts.

We can remove the listen with removeEventListener in the componentWillUnmount to clean it up.

For instance, we can write:

class Home extends Component {
  constructor(props) {
    super(props)
    this.handleScroll = this.handleScroll.bind(this);
  }

  componentDidMount() {
    window.addEventListener('scroll', this.handleScroll);
  }

  componentWillUnmount() {
    window.removeEventListener('scroll', this.handleScroll);
  }

  handleScroll(e) {
    console.log('scrolled');
    console.log(e);
  }

  render() {
    return (
     <div>
       <Foo />
       <Bar />
       <Baz />
     </div>
    );
  }
}

We added the scroll event listener in compoonentDidMount .

The handler is the this.handleScroll method.

Then we have the removeEventListener method call within componentWillUnmount .

“Using string literals in ref attributes is deprecated (react/no-string-refs)” Lint Warning

We shouldn’t be using string refs since they’re being deprecated.

Instead, we can use createRef or callback refs.

For instance, we can write:

class App extends Component {
  constructor() {
    super();
    this.btnRef = React.createRef();
    this.handleClick = this.handleClick.bind(this);
  }

  render() {
    return (
      <div>
        <button ref={this.btnRef} onClick={this.handleClick}>click me</button>
      </div>
    );
  }
}

The ref is created with createRef .

We assigned the ref to the button with the ref prop.

Also, we can assign a ref with a callback as follows:

class App extends Component {
  constructor() {
    super();
    this.btnRef;
    this.state = { clicked: false };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(){
    //...
  }

  render() {
    return (
      <div>
        <button ref={(el) => this.btnRef = el} onClick={this.handleClick}>click me</button>
      </div>
    );
  }
}

We get the element with the el parameter and then set it to this.btnRef .

Set State of Response from Axios in React

We can set the state inside the callback.

For instance, we can write:

axios.get('/url')
 .then((response) => {
   this.setState({ events: response.data })
 })
.catch(function (error) {
   console.log(error);
});

We make a GET request to a URL, then call setState on it.

We’ve to use an arrow function so that we can access the correct this , which is the component itself.

A full example would be the following:

import React from 'react';
import axios from 'axios';
export default class App extends React.Component {
  state = {
    persons: []
  }

  componentDidMount() {
    axios.get(`https://jsonplaceholder.typicode.com/users`)
      .then(({ data }) => {
        const persons = data;
        this.setState({ persons });
      })
  }

  render() {
    return (
      <div>
        { this.state.persons.map(person => <p>{person.name}</p>)}
      </div>
    )
  }
}

We make the same request and get the data from the data property of the response,

Then we call setState to update the persons state.

In the render method, we render the persons state array into paragraphs.

Detecting When User Scrolls to Bottom of div with React

We can listen for scroll events.

In the scroll event handler, we can get the getBoundClientRect method’s bottom property and compare it to the window.innerHeight to see of the div is at the bottom of the div.

For instance, we can write:

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

  isBottom(el) {
    return el.getBoundingClientRect().bottom <= window.innerHeight;
  }

  componentDidMount() {
    document.addEventListener('scroll', this.trackScrolling);
  }

  componentWillUnmount() {
    document.removeEventListener('scroll', this.trackScrolling);
  }

  trackScrolling(){
    if (this.isBottom(headerRef)) {
      document.removeEventListener('scroll', this.trackScrolling);
    }
  };

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

We create the ref with the createRef in the constructor,.

Then in componentDidMount , we listen to the scroll event.

We added the trackScrolling method to listen to the scroll event.

Then we check is we scrolled to the bottom of the div with getBoundingClientRect ‘s returned object to check if we scrolled to the bottom of the div.

Conclusion

There are various ways to check for scrolling.

Also, we shouldn’t use string refs.

And can get data from Axios and set the state to render the data.

Categories
React Tips

React Tips — External URLs, Timers, and Hover Effect

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.

Wait for setState to Finish Before Triggering a Function

We can wait for setState to finish before triggering a function by passing in a function as a 2nd argument of setState .

For instance, we can write:

this.setState({
  firstName,
  lastName,
  age
}, () => {
  console.log(this.state) ;
})

We called setState with the object with the states first.

Then we run our callback to get the latest value of this.state .

External Link with React Router

We can add an external link by passing in a component to redirect to an external link.

For instance, we can write:

<Route path='/external-site' >
  {() => {
     useEffect(() => {
       window.location.href = 'https://example.com';
     }, [])
     return null;
  }}
</Route>

We used the Router component with the path prop to set the path.

Then in our component, we redirect to an external URL by setting the URL as the value of window.location.href .

And we return null to render nothing.

We can also redirect directly in componentDidMount :

class RedirectPage extends React.Component {
  componentDidMount(){
    window.location.replace('http://www.example.com')
  }

  render(){
    return null;
  }
}

Access a Hover State in React

We can set the hove state by listening to the mouseenter and mouseleave events.

For instance, we can write:

<div
  onMouseEnter={this.onMouseEnter}
  onMouseLeave={this.onMouseLeave}
>
  foo
</div>

We can pass in event handlers to the onMouseEnter and onMouseLeave props.

Then we can run code within those methods to set the hover state.

PropTypes in Functional Stateless Component

We can set the prop types in the functional stateless component.

For instance, we can write:

import React from "react";
import PropTypes from "prop-types";

const Name = ({ name }) => <div>hi {name}</div>;

Name.propTypes = {
  name: PropTypes.string
};

Name.defaultProps = {
  name: "james"
};

We created the Name component with the propTypes property.

Then we set the data type of the name prop with it.

We can also set the default value for the name prop.

We’ve to install the propt-types package to set types for the props.

setTimeout() in React Components

We can use setTimeout in React components by calling setTimeout in componentDidMount and then clearing the timer within the componentWillMount method.

For instance, we can write:

class App extends React.Component {
  constructor() {
    this.state = { position: 0, timer: undefined };
  }

  componentDidMount() {
    const timer = setTimeout(() => this.setState({ position: 1 }), 3000)
    this.setState({ timer });
  }

  componentWillUnmount(){
    clearTimeout(this.state.timer);
  };

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

We called setTimeout with a callback with the timeout time span in componentDidMount to get the timer when the component loads.

It returns a timer object that we can call clearTimeout with to clear the resources for the timer when the component unmounts./

We have the timer state to set the timer returned from setTimeout to the state.

Then we in componentWillUnmount , we call clearTimeout to clear the timer.

setInterval in a React Component

Like with setTimeout , we can call setInterval within a React component.

It’s pretty much the same as setTimeout except that we can setInterval and clerInterval .

For instance, we write:

class App extends React.Component {
  constructor() {
    this.state = { position: 0, timer: undefined };
  }

  componentDidMount() {
    const timer = setInterval(() => this.setState(state => ({ position: state.position + 1 })), 3000)
    this.setState({ timer });
  }

  componentWillUnmount(){
    clearInterval(this.state.timer);
  };

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

We called setInterval in componentDidMount to create a timer to run code periodically.

In the setInterval callback, we update the position state every 3 seconds.

Then in componentWillUnmount , we call clearInterval to clear the timer.

With function components, we can do the same thing.

For instance, we can write:

import React, { useState, useEffect } from 'react';

const App = () => {
  const [position, setPosition] = useState(0);
  const timer = () => setPosition(position => position + 1);

  useEffect(() => {
    const timer = setInterval(timer, 1000);
    return () => clearInterval(timer);
  }, []);

  return <div>{position}</div>;
};

We have the useState hook to update the position state with setPosiitin .

Then we have the useEffect hook to create a timer when the component loads.

Then function we return in the useEffect callback removes the timer with clearInterval .

The empty array in the 2nd argument ensures that the useEffect callback only runs when App first loads.

Conclusion

We can create a component to redirect to an external URL.

Also, we can use setTimeout and setInterval in our components.

To set prop types, we can use the prop-types package.

Categories
React Tips

React Tips — Detect KeyPress, Unique IDs, and Remove 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.

Generate Unique IDs for Form Labels in React

We can generate unique IDs with the Lodash or Underscpre’s uniqueId method.

For instance, we can write:

class App extends React.Component {
  `constructor(props) {
    super(props);
    this.id = _.uniqueId("form-");
  }

  render() {
    const id = this.id;
    return (
      <div>
        <input id={id} type="text" />
        <label htmlFor={id}>label</label>
      </div>
    );
  }
}`

We called uniqueId and assigned the returned value as the value of the id prop.

The argument for the method is the prefix for the ID.

With function components, we can write:

import React, { useState } from 'react';
import uniqueId from 'lodash/uniqueId';

const App = (props) => {
  const [id] = useState(uniqueId('form-'));
  return (
    <div>
      <input id={id} type="text" />
      <label htmlFor={id}>label</label>
    </div>
  );
}

We imported the uniqueId function and then put it in useState .

This way, we can get the ID as variable and use it in our form child elements.

Detect Esc Key Press in React

We can detect the Esc key by adding a keydown event handler into our component.

For instance, we can write:

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

  onKeyPress(event){
    if(event.keyCode === 27) {
      //...
    }
  }

  componentDidMount(){
    document.addEventListener("keydown", this.onKeyPress, false);
  }

  componentWillUnmount(){
    document.removeEventListener("keydown", this.onKeyPress, false);
  }

  render(){
    return (
      <input />
    )
  }
}

We add an event listener for the keydown event by calling documebnt.addEventListener in the componentDidMount method.

This will ensure that the event listener is added when the component mounts.

Likewise, we can removeEventListener to remove the event listener to ensure that it’s unloaded when the component unmounts.

this.onKeypress is the event handler.

In the method, we check the keyCode property to get the code for the key pressed.

27 is the code for the Esc key.

With function components, we can use the useEffect hook to add and remove the listener.

For instance, we can write:

import React, { useEffect } from 'react';

const App = () => {

  useEffect(() => {
    const handleEsc = (event) => {
       if (event.keyCode === 27) {
        console.log('Close')
      }
    };
    window.addEventListener('keydown', handleEsc);

    return () => {
      window.removeEventListener('keydown', handleEsc);
    };
  }, []);

  return(<p><input /></p>);
}

We have the useEffect hook with a callback to add the keydown listener.

We call addEventListener when the component mounts with addEventListener .

The empty array in the 2nd argument ensure that it loads only when the component mounts,

We call removeEventListener when the component unmounts to remove the listener when it unmounts.

The event listener code is the same as the previous example.

Delete Item from State Array in React

We can delete an item from a state array by calling splice on the original array and then calling setState to set that as the new value of the state array.

For instance, we can write:

removePeople(e) {
  const people = [...this.state.people];
  const index = array.indexOf(e.target.value);
  if (index !== -1) {
    people.splice(index, 1);
    this.setState({ people });
  }
},

First, we make a copy of the array so that we can modify it without changing the original array.

Then we get the index that we want to remove.

Then we call splice to remove the item from the array copy.

And then we call setState to set that as the new value.

We can also use the filter method to return a new array that includes the items that we want to keep.

For example, we can write:

class ItemsList extends Component {
  constructor() {
    this.state = {
      itemsList: [
        {
          id: 1,
          name: 'All Items',
        }, {
          id: 2,
          name: 'In Stock Items',
        }
      ],
    }
     this.removeItem = this.removeItem.bind(this)
  }

  removeItem(deleteItemId) {
     this.setState({
       itemsList: this.state.itemsList.filter(item => item.id != deleteItemId)
        })
   }

  render(){
    return <div />
  }
}

We called filter to return a new array that includes only the items with id value other than deleteItemId .

Then we call setState to set that as the new value of itemsList state.

Conclusion

We can generate unique ID with Underscore or Lodash methods.

There are a few ways to remove an item from a state array.

And there are multiple ways to detect Esc key press.

Categories
React Tips

React Tips — Mock React-Redux, Internationalization, and Connect Redux with React

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.

How to Unit Test React-Redux Connected Components

We can test a React-Redux connected component by mocking the connect function and Provider component with our own code.

For instance, we can write:

jest.mock('react-redux', () => {
  return {
    connect: (mapStateToProps, mapDispatchToProps) => (Component) => ({
      mapStateToProps,
      mapDispatchToProps,
      Component
    }),
    Provider: ({ children }) => children
  }
})

We create a mock version of React Redyx by creating a mock module with the connect function.

It takes a mapStateToProps and mapDispatchToProps methods like the real thing.

And it returns a function that takes a React component and returns an object with all the parameters in it.

To mock the Provider we just return the children from the prop.

This can be used inline within a file.

To put the mock in a separate file, we can write:

module.exports = {
  connect: (mapStateToProps, mapDispatchToProps) => (Component) => ({
    mapStateToProps,
    mapDispatchToProps,
    Component,
  }),
  Provider: ({children}) => children
};

in __mocks__/react-redux.js .

The __mocks__ folder should be in the root folder.

Unless we call jest.unmock(‘react-redux’)) the mock will be used.

PropTypes in Stateless Functional Component

We can set prop types in stateless function components.

For instance, we can write:

import React from 'react';
import PropTypes from 'prop-types';

function List(props) {
  const todos = props.todos.map((todo, index) => (<p key={index}>{todo}</p>));
  return (<div>{todos}</div>);
}

List.propTypes = {
  todos: PropTypes.array.isRequired,
};

We assign the propTypes property with an object with the prop types.

And then we use the PropTypes object to specify the type.

How to Maintain State After a Page Refresh in React

To maintain state after a page refresh in React, we can store the state we want to keep in local storage.

For instance, we can write:

constructor() {
  const selectedOption = localStorage.getItem('selectedOption');
  this.state = {
    selectedOption
  };
}

setSelectedOption(option) {
  localStorage.setItem('selectedOption', option);
  this.setState({ selectedOption: option });
}

We have the constructor that gets the saved state from local storage with getItem .

Then in another method, we set the option in the local storage and the state.

Use Redux’s Store with React

To access a Redux store with a React component, we can use the connect function.

For instance, we can write:

import { connect } from 'react-redux'
import { setVisibilityFilter } from '../actions'
import Link from '../components/Link'

const mapStateToProps = (state, ownProps) => {
  return {
    active: ownProps.name === state.name
  }
}

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    onClick: () => {
      dispatch(setName(ownProps.name))
    }
  }
}

const NameLink = connect(
  mapStateToProps,
  mapDispatchToProps
)(Link)

export default NameLink

With our mapStateToProps function, we return the active Redux state as a prop for the Link component.

Also, we have the mapDispatchToProps function to let us create a function that calls dispatch dispatch an action to our Redux store.

Then we can pass them all to the connect function, which returns a higher-order component.

Then we can pass in our Link component to return a new component to add the state and dispatch functions as props.

How to use FormattedMessage in input placeholder with React-Intl

To pass in a placeholder that’s translated with the react-intl, we can call the formatNwessage method with an object to interpolate the placeholders.

For instance, we can write:

import React from 'react';
import { injectIntl, intlShape } from 'react-intl';

const Input = ({ intl }) => {
  const placeholder = intl.formatMessage({ id: 'messageId' });
  return(
     <input placeholder={placeholder} />
  );
}

Input.propTypes = {
  intl: intlShape.isRequired
}

export default injectIntl(Input);

We use the injectIntl higher-order component to inject the intl prop to our component.

It has the formatMessage method that we can interpolate our placeholders with.

It returns a string so that we can use it in in our placeholder prop.

With function components, we can use the useIntl hook to do the same thing.

For instance, we can write:

import React from 'react';
import { useIntl } from 'react-intl';

const Input = () => {
  const intl = useIntl();
  const placeholder = intl.formatMessage({ id: 'messageId' });
  return(
     <input placeholder={placeholder} />
  );
};

export default Input;

We use the useIntl hook to get the intl object.

Then we can call formatMessage on it to interpolate our string.

Conclusion

We can use the react-intl for internationalization.

Also, the react-redux module can be mocked in our tests.

Props types can be set in function components.

We can save our state to local storage to make it persist during refresh.

Categories
React Tips

React Tips — Form Validation, Links, and Isomorphic Components

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.

Form Input Validation with React

We can do form validation with our own checks.

For instance, we can do the value checks within the submit handler.

We can write:

class Signup extends React.Component{
  constructor(props){
    super(props);
     this.state = {
       isDisabled:true
     }
     this.submitForm = this.submitForm.bind(this);
  }

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

    if (e.target.name==='firstname'){
      if (e.target.value === '' || e.target.value === null){
        this.setState({
          firstnameError: true
        })
      } else {
        this.setState({
          firstnameError: false,
          firstName: e.target.value
        })
      }
    }

    if (e.target.name==='lastname'){
      if(e.target.value==='' || e.target.value === null) {
        this.setState({
          lastnameError: true
        })
      } else {
        this.setState({
          lastnameError:false,
          lastName:e.target.value
        })
      }
    }

  }

  submitForm(e){
    e.preventDefault();
    const data = {
     firstName: this.state.firstName,
     lastName: this.state.lastName
    }
  }

  render(){
    return (
      <form>
        <div>
          <input type="text" id="firstname" name="firstname" placeholder="firstname" onChange={(e)=>{this.handleChange(e)}} />
          <label htmlFor="firstname">firstname</label>
            {this.state.firstnameError ? 'Please Enter some value' : ''}
        </label>
        <div>
           <input type="text" name="lastname" placeholder="lastname" onChange={(e)=>{this.handleChange(e)}} />
            <label htmlFor="lastname">lastname</label>
              {this.state.lastnameError ? '>Please Enter some value' : ''}
            </label>
         </div>
         <button onClick={this.submitForm}>Signup</button>
      </form>
    );
  }
}

We have the first name and last name fields.

We watch for their inputted values and check for them in the handleChange method.

target.name has the value of the name attribute.

target.value has the inputted value.

And then in each field, we check if it’s filled in.

In the submitForm method, we get the data and then submit it.

We’ve to call preventDefault to stop the default submit behavior.

To make our lives easier, we can use a package like React Hook Forms to do form validation.

For instacne, we can write:

import React from "react";
import useForm from 'react-hook-form';

function Form() {
  const { useForm, register } = useForm();
  const contactSubmit = data => {
    console.log(data);
  };

  return (
    <form onSubmit={contactSubmit}>
      <div className="col-md-6">
        <fieldset>
          <input name="name" type="text" size="30" placeholder="Name" ref={register} />
          <br />
          <input name="email" type="text" size="30" placeholder="Email" ref={register} />
        </fieldset>
        <fieldset>
          <button id="submit" value="Submit">
            Submit
          </button>
        </fieldset>
      </div>
    </form>
  );
}

We use the useForm hook that comes with the package.

And then we call register returned from useForm to get register the input fields so that we get the form values with the submit handler.

The values are in the data parameter of the contactSubmit function.

Importing CSS files in Isomorphic React Components

In isomorphic React components, we can check for the environment before we import our CSS.

For instance, we can write:

if (process.env.BROWSER) {
  require("./style.css");
}

We check the environment variables before we import the CSS.

We import only in the browser environment.

We can then define a Webpack plugin to set the environment variable:

plugins: [
  // ...
  new webpack.DefinePlugin({
    "process.env": {
      BROWSER: JSON.stringify(true)
    }
  })
]

How to Render Child Components in React Recursively

We can render child components recursively by rendering the same component within the component.

For instance, we can write:

import React, { Component, PropTypes } from 'react'

export default class Comments extends Component {

render() {
    const { comments } = this.props;

    return (
      <div>
        {comments.map(comment =>
          <div key={comment.id}>
            <span>{comment.content}</span>
            {comment.comments && <Comments comment={comment.comments} />}
          </div>
        )}
      </div>
    )
  }
}

Comments.propTypes = {
  comments: PropTypes.array.isRequired
}

We create a Comment component that takes a comments prop that’s rendered into an array of Comment components.

We make the comments prop required and an array so that we can render them if they’re passed in.

React-Router is Refreshing the Page when Using a Tag

To stop refreshing the page when we click an a tag, we should use the Link component.

For instance, we can write:

import React from "react";
import { Link } from 'react-router-dom';

export class App extends React.Component {
  render() {
    return (
      <Link to="/foo">Click Here</Link>
    )
  }
};

We use the Link tag with the to prop that has the route.

Conclusion

We can validate form inputs in many ways.

To make our lives easier, we should use a form validation library

Also, we check the environment before we import CSS in an isomorphic React component.

We use the Link component for links if we use React Router.