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.

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.