Categories
React Tips

React Tips — SVGs and Scroll Events

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.

Embedding SVG into ReactJS

We can put SVG code straight into our React component

For instance, we can write:

function SvgApple() {
  return (
       <svg id="svg2" viewBox="0 0 624.38 604.71" version="1.0">
      <defs id="defs3">
        <linearGradient
          id="linearGradient2847"
          x1="340.66"
          gradientUnits="userSpaceOnUse"
          y1="322.86"
          gradientTransform="translate(164.44 185.74)"
          x2="398.88"
          y2="322.86"
        >
          <stop id="stop2831" stop-color="#ccc" offset="0" />
          <stop id="stop2833" stop-color="#ccc" stop-opacity="0" offset="1" />
        </linearGradient>
        <radialGradient
          id="radialGradient2849"
          gradientUnits="userSpaceOnUse"
          cy="586.46"
          cx="366.79"
          gradientTransform="matrix(1 0 0 .90909 246.44 239.05)"
          r="258.49"
        >
          <stop id="stop2807" stop-color="#e6e6e6" offset="0" />
          <stop
            id="stop2809"
            stop-color="#e6e6e6"
            stop-opacity="0"
            offset="1"
          />
        </radialGradient>
        <radialGradient
          id="radialGradient2851"
          gradientUnits="userSpaceOnUse"
          cy="274.22"
          cx="490.32"
          gradientTransform="matrix(1 0 0 .61041 168.44 290.57)"
          r="123.39"
        >
          <stop id="stop2821" stop-color="#ccc" offset="0" />
          <stop id="stop2823" stop-color="#ccc" stop-opacity="0" offset="1" />
        </radialGradient>
      </defs>
      <g id="layer1" transform="translate(-89.704 -231.29)">
        <g
          id="g2837"
          transform="matrix(.93776 .34729 -.34729 .93776 206.95 -108.99)"
        >
          <path
            id="path10856"
            stroke="#000"
            transform="translate(731.28 508.81)"
            d="m-320.82 328.99c1.62-1.61-22.63-13.81-20.59-14.85 2.03-1.04-2.35 25.75-0.09 25.39 2.25-0.36-10.2-24.47-7.94-24.12 2.26 0.36-17.03 19.45-15 20.49 2.04 1.04 6.14-25.79 7.76-24.18 1.62 1.62-25.21 5.73-24.17 7.76 1.03 2.04 20.12-17.25 20.48-15 0.36 2.26-23.76-10.19-24.12-7.93-0.35 2.26 26.43-2.13 25.39-0.09-1.03 2.03-13.23-22.21-14.85-20.6-1.61 1.62 22.63 13.81 20.6 14.85-2.04 1.04 2.35-25.75 0.09-25.39s10.19 24.48 7.94 24.12c-2.26-0.36 17.03-19.45 14.99-20.49-2.03-1.03-6.14 25.79-7.75 24.18-1.62-1.62 25.21-5.72 24.17-7.76s-20.13 17.26-20.48 15c-0.36-2.26 23.76 10.19 24.11 7.93 0.36-2.25-26.42 2.13-25.39 0.1 1.04-2.04 13.24 22.21 14.85 20.59z"
          />
          <path
            id="path10853"
            stroke="#000"
            fill="red"
            d="m625.29 586.46c0 138.74-115.81 235-258.5 235-142.68 0-258.49-96.26-258.49-235s115.81-234.99 258.49-234.99c142.69 0 258.5 96.25 258.5 234.99z"
          />
          <path
            id="rect10858"
            stroke="#000"
            stroke-width=".62806"
            fill="#803300"
            d="m381.01 236.85c8.59 0 17.56 0.03 17.56 0.07l-14.31 171.88c0 0.04-6.92 0.07-15.51 0.07s-15.51-0.03-15.51-0.07l-12.26-171.88c0-0.04 31.44-0.07 40.03-0.07z"
          />
          <path
            id="path2827"
            opacity=".6729"
            fill="url(#linearGradient2847)"
            d="m381.01 236.85c8.59 0 17.56 0.03 17.56 0.07l-14.31 171.88c0 0.04-6.92 0.07-15.51 0.07s-15.51-0.03-15.51-0.07l-12.26-171.88c0-0.04 31.44-0.07 40.03-0.07z"
          />
          <path
            id="path10861"
            stroke="#000"
            stroke-width="3.063"
            fill="none"
            d="m337 394.28c2.62 5 12.11 14.08 19.7 14.09 7.77 0.02 27.78 0.58 29.61-1.57 3-3.54 10.81-15.89 12.33-20.76"
          />
          <path
            id="path10868"
            stroke="#000"
            stroke-width=".35974"
            fill="#338000"
            d="m538.62 313.49c-56.1 31.56-164.82 43.23-171.29 31.7-6.46-11.54 64.93-89.87 121.02-121.43 56.1-31.56 117.89-28.15 124.35-16.61 6.46 11.53-17.99 74.78-74.08 106.34z"
          />
          <path
            id="path2803"
            opacity=".40654"
            fill="url(#radialGradient2849)"
            d="m707.29 586.46c0 138.74-115.81 235-258.5 235-142.68 0-258.49-96.26-258.49-235s115.81-234.99 258.49-234.99c142.69 0 258.5 96.25 258.5 234.99z"
          />
          <path
            id="path2817"
            opacity=".78364"
            fill="url(#radialGradient2851)"
            d="m542.62 311.49c-56.1 31.56-164.82 43.23-171.29 31.7-6.46-11.54 64.93-89.87 121.02-121.43 56.1-31.56 117.89-28.15 124.35-16.61 6.46 11.53-17.99 74.78-74.08 106.34z"
          />
        </g>
      </g>
    </svg>
  );
}

We added an SVG of an apple from https://publicdomainvectors.org/en/free-clipart/Apple-vector-drawing/2168.html by removing all the namespaced tags from the original SVG code.

Update Style of a Component onScroll in React

We can listen to scroll events by attaching a scroll event listener in our component.

For instance, we can write:

class App extends React.Component {
  constructor(){
    this.state = {}
  }

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

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

  handleScroll() {
    const scrollY = window.scrollY;

    this.setState({
      scrollY
    });
  }

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

We attached the scroll event listener with the addEventListener method in the componentDidMount method to add the event listener when the component mounts.

Then we call the removeEventListener to remove the listener.

handleScroll is our listener.

We get the scroll distance with the window.scrollY property.

And we call setState to set the scrollY state so that we can use it anywhere in our component.

In the componentWillUnmount method, we remove the scroll event listener when the component unmounts.

If we have a function component, we write:

import React, { useState, useEffect } from "react"

const ScrollingElement = () => {
  const [scrollY, setScrollY] = useState(0);

  function handleScroll() {
    setScrollY(window.scrollY);
  }

  useEffect(() => {
    function watchScroll() {
      window.addEventListener("scroll", handleScroll);
    }
    watchScroll();

    return () => {
      window.removeEventListener("scroll", handleScroll);
    };
  }, []);

  return (
    <div>
      <div>{scrollY}px</div>
    </div>
  );
}

The code is equivalent to class example.

We add the listen in the useEffect callback to listen to the scroll event.

Then we stop listen by removing the listener within the callback that’s returned in the useEffect callback.

The handler calls the setScrollY function to set the scrollY state.

Conclusion

We can embed SVG directly in our React component as long as we remove all the namespaced tags.

To listen for scroll events, we attach a scroll event listener within our component.

Categories
React Tips

React Tips — Pass Props, Background Image, and Window Resize

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.

Pass Props to Handler Component with React Router

We can pass props to the route handler component with render props.

For instance, we can write:

<Route path="/greeting/:name" render={(props) => <Greeting greeting="Hello, " {...props} />} />

Then we can define our Greeting component by writing:

class Greeting extends React.Component {
  render() {
    const { text, match: {params} } = this.props;
    const { name } = params;

    return (
      <>
        <p>
          {text} {name}
        </p>
      </>
    );
  }
}

We pas in props from the parameter to the Greeting component.

Then we get the props from the this.props property in Greetings .

Then we can do whatever we want with it.

Rerender View on Browser Resize

We can watch for window resize with a hooked if we’re using function components.

For instance, we can write:

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

function useWindowSize() {
  const [size, setSize] = useState([0, 0]);
  useLayoutEffect(() => {
    function updateSize() {
      setSize([window.innerWidth, window.innerHeight]);
    }
    window.addEventListener('resize', updateSize);
    updateSize();
    return () => window.removeEventListener('resize', updateSize);
  }, []);
  return size;
}

function App() {
  const [width, height] = useWindowSize();
  return <span>{width} x {height}</span>;
}

We created the useWindowSize hook that watches the window size change by adding an event listener for the resize event.

Then when we return the function to clean up the code, we call removeEventListener to remove the event listener.

We set the size state in the event handler.

The window.innerWidth has the window width and the window.innerHeight has the window height.

Then we can get it the latest values by using our hook in a component.

We create our own hook to encapsulate our logic so that we don’t have to spread them in our code.

Also, we can reuse it anywhere, which is another benefit.

In class components, we can also watch the resize event.

For instance, we can write:

import React from 'react';

class App extends React.Component {
  state = { width: 0, height: 0 };
  render() {
    return <span>{this.state.width} x {this.state.height}</span>;
  }

  updateDimensions = () => {
    this.setState({ width: window.innerWidth, height: window.innerHeight });
  };

  componentDidMount() {
    window.addEventListener('resize', this.updateDimensions);
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.updateDimensions);
  }
}

We have the updateDiemsions method to set the window width and height with setState .

Then we call addEventListener in componentDidMount to listen to window size changes.

And we call removeEventListener to remove the listener when the component unmounts.

In the render method, we render the window size.

Fix ‘Uncaught TypeError: Cannot read property ‘setState’ of undefined’ Error

We can fix the setState is undefined error by calling bind on the method that we’re calling in our class component.

For instance, we write:

constructor(props) {
  super(props);
  this.state = {
    count: 1
  };

  this.setCount = this.setCount.bind(this);
}

We call this.setCount.bind(this) to set the value of this of this.setCount to the component.

We call it in the constructor so that we don’t have to call bind multiple times anywhere else.

Also, we can use an arrow function instead.

For instance, we can write:

setCount ` = () => {
  this.setState({
    count : this.state.count + 1
  });
}`

in our component class.

React Router with an Optional Path Parameter

We can add an optional path parameter by adding a question mark to the path parameter.

For instance, we can write:

<Route path="/to/page/:pathParam?" component={Page} />

for one optional parameter.

If we want more, we can write:

<Route path="/to/page/:foo?/:bar?" component={Page} />

This is applicable to version 4 or later.

Setting a Background Image With React Inline Styles

We can set the background image with React inline styles by writing:

backgroundImage: `url(${Background})`

inside the object that we pass into the styles prop.

Backgeround is the image that we imported as a module.

An image can be imported as a module with Webpack.

Conclusion

We can set the background image by import the image as a module and setting that as the value of the background image.

To get the size of the window, we can listen to the resize event.

We can pass props to a route handling component with React Router.

Categories
React Tips

React Tips — Fix Common Errors, Multiple Classes, and Context API

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.

Add Multiple Classes to a React Component

We can use the classnames package to add multiple classes to a React component.

For instance, in the render method or the function component, we can write:

const liClasses = classNames({
  'main-class': true,
  'active': props.active
});

return (<li className={liClasses}>{props.name}</li>);

We can also use template literals to do the same thing.

For instance, we can write:

<input className={`form-control rounded ${this.state.valid ? '' : 'error'}`} />

Fix the ‘Invariant Violation: Objects are not valid as a React child’ Error

We can fix the error by making sure that we have strings or components in between the opening and closing tags of a wrapper component.

For instance, if we’re rendering a string, we can write:

return (
  <Item href={routeString}>
    {breadcrumbElement}
  </Item>
)

where breadcrumbElement is a React element or component.

We can also replace the element or component with a string:

return (
  <Item href={routeString}>
    hello world
  </Item>
)

If we have an array, we can write:

const photosList = photos.map((photo, i) => {
  return (
    <div>
       <img src={photo.url} alt={photos.description} />
    </div>
  );
});

return (
  {photosList}
);

These are all inside the render method of a class component or a function.

We have an expression to render the photos array into images by call map with a callback that returns an img element.

Then we return that in our return statement.

Fix the ‘A component is changing an uncontrolled input of type text to be controlled’ Error

We can fix the error by setting the value prop of our input with a state.

To set the state, we pass an event handler to the onChange prop to set the state when the input value changes.

For instance, we can write:

<input
  className="input"
  type="text"
  value={this.state.name || ""}
  name="name"
  placeholder="name"
  onChange={this.onChange}
/>

Then in our onChange method, we can write:

onChange(event){
  const { name, value } = event.target;
  this.setState(prevState => {
    prevState.fields[name] =  value;
    return {
      fields: prevState.fields
    };
  });
};

We get the name and value properties from event.target .

Then we call setState with a callback to merge the new value with the existing state object.

Two React Components Communicating

There are a few scenarios where React components communicate.

The most common is parent-child communication.

For instance, we can write:

const Child = ({ onClick }) => (
  <div onClick={() => onClick(42)}>
    Click me
  </div>
);

class Parent extends React.Component {
  onClick(value){
    console.log(value);
  };

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

We have the onClick method in Parent that we pass to the Child component.

Then we get the onClick from the props from the props parameter.

Then we pass that to the onClick callback where we call it with a value.

Then the console.log will run.

If we want to communicate between components that have other relationships, we can use the Context API.

For instance, we can write:

const AppContext = React.createContext(null)

class App extends React.Component {
  render() {
    return (
      <AppContext.Provider value={{ language: "en" }}>
        <div>
          <Foo>
            <Bar>
              <Baz />
            </Bar>
          </Foo>
        </div>
      </AppContext.Provider>
    )
  }
};

const Baz = () => (
  <AppContext.Consumer>
    {({language}) => <div>{language}</div>}
  </AppContext.Consumer>
);

We call the React.createContext to created the context.

Then we can use the AppContext.Provider to pass the data into any components that are inside the AppContext.Provider .

The value prop has the data that we can access elsewhere.

Since our Baz component is inside our context provider, we can use the AppContext.Consumer to get the data and render it.

We have a callback inside it to get the language from the object we passed into value .

Conclusion

We can add multiple classes to a component with a template string or the classnames package.

We can communicate between parent and child components directly.

Or we can use the context API to communicate between any component.

Various errors can be solved with quick fixes.

Categories
React Tips

React Tips — create-react-app, Disable Buttons, and Current Routes

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 get Current Route with React Router

We can use the useLocation hook to get the current route with React Router.

For instance, we can write:

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

function App() {
  const location = useLocation();
  return <span>{location.pathname}</span>
}

useLocation returns the nativelocation object.

So we can use location.pathname to get the current route.

With class components, we can use the withRouter higher-order component to set the location prop to do the same thing.

For instance, we can write:

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

const App = withRouter(props => <Foo {...props}/>);

class Foo extends React.Component {
  bar() {
    const {pathname} = this.props.location;
  }
}

We called the withRouter higher-order component and pass in the props from there into our Foo component.

This sets the locations prop of Foo to the native location object.

Then we can get the pathname for the path.

Services in React Application

A service is just a context-independent piece of code which we can reuse anywhere.

So to make a service in a React app, we can just make a module that exports an object with the shared methods that we want to call.

For instance, we can write:

const HttpService = {
  getTodos(value) {
     // code to get todos
  },

  setTodos(value) {
     // code to save todos
  }
};

export default HttpService;

Then in our component, we can write:

import HttpService from "./services/HttpService.js";

function TodosPage() {
  const [todos, setTodos] = useState([]);
  const getTodos = async () => {
    const todos = await HttpService.getTodos();
    setTodos(todos);
  }

  useEffect(() => {
    getTodos()
  }, [])

  return <Todos todos={todos} />
}

We just import the module and then use the getTodos method within the export object to get the data we want.

We can do the same thing for any other piece of context-independent shared code.

Disable a Button When an Input is Empty

We can disable a button when an input field is empty by checking the input’s value and determine if we need to disable button.

For instance, we can write:

class EmailForm extends React.Component {
  constructor() {
    super();
    this.state = {
      email: '',
    };
  }

  handleEmailChange = (evt) => {
    this.setState({ email: evt.target.value });
  }

  handleSubmit = () => {
    const { email } = this.state;
    alert(`${email} subscribed`);
  }

  render() {
    const { email} = this.state;
    const enabled = email.length > 0;
    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type="text"
          placeholder="Email"
          value={this.state.email}
          onChange={this.handleEmailChange}
        />

        <button disabled={!enabled}>Subscribe</button>
      </form>
    )
  }
}

We created an input for entering an email address.

When we enter something into the input, then the handleEmailChange method runs.

It sets the email state which we use in the value prop of the input and in the render method for the button enabled check.

We set the enabled flag by checking if the email’s length is bigger than 0.

This means that something is filled into the box.

Then we set the disabled prop of the button to be !enabled to disable it when it’s empty.

The Use of the ‘react-scripts start’ Command

react-scripts is a set of scripts that’s provided by create-react-app .

It kicks off our project without configuration, so we don’t have to set up a React project from scratch ourselves.

react-scripts start sets up the dev environment and runs the dev server and enables hot reloading.

It has React, JSX, ES6, and Flow syntax support.

ES features beyond ES6 like the object spread operator can also be used.

CSS is autoprefixed so that we don’t have to add the prefixes ourselves.

A create-react-app project also comes with a unit test runner.

It’ll also warn us about common developer mistakes.

And it’ll compile the app for us into a production-ready bundle.

It also supports the development of progressive web apps.

All the tolls will be updated when we update create-react-app.

Conclusion

We can create a shared module to reuse context independent code.

create-react-app does a lot for us, so we should use it to create React apps.

There are a few ways to get the current route with React Router.

We can disable a button by setting a boolean expression as the value of the disabled prop.

Categories
React Tips

React Tips — Function Props, Query Strings, and Default Props

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.

Listen to State Changes in React

We can listen to state changes to React in several ways.

In class components, we can use the componentDidUpdate hook to listen for state and prop changes.

We can write:

componentDidUpdate(object prevProps, object prevState)

There’s also the componentWillUpdate method which is deprecated.

With function components, we can use the useEffect hook to watch for changes.

For instance, we can write:

const [name, setName] = useState('foo');
useEffect(getSearchResults, [name])

We pass in an array with the variables that we want to watch in the 2nd argument of the useEffect hook.

The first argument is a callback that’s called when name changes.

Pass Props in Link with React Router

We can pass in a query string to the Link .

For instance, we can write:

<Link to={{ pathname: `/foo/bar`, query: { backUrl } }} />

We set the query property with an object.

The object’s keys and values are transformed into a query string that’s attached after the pathname .

We can also take URL parameters with placeholders:

<Route name="/foo/:value" handler={CreateIdeaView} />

Then we can get it by using:

this.props.match.params.value

To get the query string, we can write:

this.props.location.search

to get the value.

Then we can use the URLSearchParams constructor to parse it and the values in it:

new URLSearchParams(this.props.location.search).get("foo")

If we have a query string ?foo=bar , then that will return 'bar' .

Call Parent Method with React

We can call a parent component’s method if we pass a function from the parent to the child as a prop.

For instance, we can write:

import React, {Component} from 'react';

class Child extends Component {
  render () {
    return (
      <div>
        <button
          onClick={() => this.props.someFunc('foo')}
        >
          click me
        </button>
      </div>
    )
  }
}

class Parent extends Component {
  someFunc(value) {
    console.log(value)
  }

  render() {
    return (
      <div>
        <Child
          someFunc={this.someFunc.bind(this)}
        />
      </div>
    )
  }

}

We pass the function from parent to child with the someFunc prop in the Parent component.

Then in the Child component, we call the function with this.props.someFunc .

Using function components, we can write:

import React from "react";

function Child(props){
  return(
    <>
      <button onClick={props.parentFunc}>
        click me
      </button>
    </>
  );
}

function Parent(){
  const parentFunc = () => {
    console.log("parent func called");
  }

  return (
    <>
      <Child
        parentFunc={parentFunc}
      />
    </>
  );
}

We have the Parent component which has the parentFunc that we pass to the Child component as a prop.

Then we called it by calling props.parentFunc when we click on the button in the Child component.

Import and Export Components Using React, ES6 and Webpack

To export components in a React project, we should export it as a default export.

For instance, we can write:

SomeNavBar.js

import React from 'react';
import Navbar from 'react-bootstrap/lib/Navbar';

export default class SomeNavBar extends React.Component {
  render(){
    return (
      <Navbar className="navbar-dark" fluid>
        {//...}
      </Navbar>
    );
  }
}

Then we import it with whatever name we want.

For instance, we can write:

import SomeNavBar from './SomeNavBar';

to import the navbar component.

We don’t put curly braces in default exports.

Set component Default Props on React Component

To set default props on a React component, we can use the prop-types package.

We’ve to install it by running:

npm i prop-types

Then we can write:

import PropTypes from 'prop-types';

class Address extends React.Component {
  render() {
    const { street, city } = this.props;
    <p>{street}, {city}</p>
  }
}

Address.defaultProps = {
  street: 'street',
  city: 'city',
};

Address.propTypes = {
  street: PropTypes.string.isRequired,
  city: PropTypes.string.isRequired
}

We set the defaultProps property to set the default prop values.

The object has the prop names as the keys and the default values as the values.

propTypes has the prop types for each prop.

We set them both to string and make them required with isRequired .

Conclusion

We can set default props and validate their format with the prop-types package.

We listen to state changes with class component lifecycle methods or the useEffect hook for function components.

Also, we can get and set query strings and URL parameters with React Router.

We can pass functions as props from parent to child.