Categories
React Tips

React Tips — SSR, Link Underline, and Authorization Header

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.

Server-Side Rendering of React Components

We can do server-side rendering with React and React Router.

For instance, we can write:

const Router = require('react-router');
const React = require("react");
const url = require("fast-url-parser");

const routeHandler = (req, res, next) => {
   const path = url.parse(req.url).pathname;
   if (/^/?api/i.test(path)) {
     return next();
   }
   Router.run(routes, path, (Handler, state) => {
     const markup = React.renderToString(<Handler routerState={state} />);
     const locals = { markup };
     res.render("main", locals);
  });
};

app.get('/', routeHandler);
app.listen(3000);

We call Router.run to route the routes for the front end to what we want.

In the Router.run callback, we run React.renderToString to render our Handler component to a static strung.

Then we pass it into the locals object and pass it off to the 'main' template.

Without React Router, we can write:

import React from 'react'
import ReactDOM from 'react-dom/server'
const express = require('express');
const app = express();

const Hello = (props) => {
  return (
    <div>
      <p>hello</p>
    </div>
  )
}

app.get('/', (req, res) => {
  const app = ReactDOM.renderToString(<Hello />)
  const html = `<!doctype html>
    <html>
      <head>${styles}</head>
      <body>
        <div id="root">${app}</div>
      </body>
    </html>`
  res.end(html)
})

app.listen(3000)

We use Express as we did in the previous example, but we removed the Reactv Router part.

We just call ReactDOM.renderToString to render the component to a string.

Then we render it straight as HTML.

In both examples, we can’t add anything dynamic to our components like event handlers or state changes to our components since it’s been rendered as a static string.

If we need all that, then we can use frameworks like Next.js to make adding dynamic features much easier.

Get Rid of Underline for Link Component of React Router

We can get rid of the underline for the Link component by changing some styles.

For instance, we can use styled-components and write:

import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import styled from 'styled-components';

const StyledLink = styled(Link)`
  text-decoration: none;
  &:focus, &:hover, &:visited, &:link, &:active {
    text-decoration: none;
  }
`;

export default (props) => <StyledLink {...props} />;

We pass in the Link component to the styled tag so that we can style it.

We applied text-decoration: none on the link and all its pseudoclasses to make remove the underline.

If we’re only styling one link, we can also write:

<Link style={{ textDecoration: 'none' }} to="/home">
  Home
</Link>

We pass in an object to the style tag to style it.

We also added textDecoration: 'none' to remove the underline.

Attach Authorization Header for All Axios Requests

If we’re using Axios in our React app, we can add an authorization header to all requests to using its request interceptor feature.

For instance, we can write:

axios.interceptors.request.use((config) => {
  const token = store.getState().token;
  config.headers.Authorization =  token;
  return config;
});

We get the header from a central store and then set that as the value of the Authorization header by setting the returned value as the value of the config.headers.Authorization property.

We can also create our own shared module that calls the Axios requests as follows:

import axios from 'axios';

const httpClient = (token) => {
  const defaultOptions = {
    headers: {
      Authorization: token,
    },
  };

  return {
    get: (url, options = {}) => axios.get(url, { ...defaultOptions, ...options }),
    post: (url, data, options = {}) => axios.post(url, data, { ...defaultOptions, ...options }),
    put: (url, data, options = {}) => axios.put(url, data, { ...defaultOptions, ...options }),
    delete: (url, options = {}) => axios.delete(url, { ...defaultOptions, ...options }),
  };
};

We have a client function that gets the token and returns an object with common HTTP request methods with the request options, which includes the token merged into the options.

Then we can reuse that anywhere:

const request = httpClient('secret');
request.get('http://example.com');

Conclusion

We can do server-side rendering with React, React Router and Express,

To get rid of the underline of a React Router link, we can pass in styles to remove it in various ways.

There are also multiple ways to pass a token to all routes into all Axios requests.

Categories
React Tips

React Tips — Scroll, Navigate, and Keeping Focus

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.

React Router Scroll to Top on Every Transition with Hooks

We can create a wrapper component to scroll a route component to the top whenever we navigate.

For instance, we can write:

import React, { useEffect, Fragment } from 'react';
import { withRouter } from 'react-router-dom';

function ScrollToTop({ history, children }) {
  useEffect(() => {
    const unlisten = history.listen(() => {
      window.scrollTo(0, 0);
    });
    return () => {
      unlisten();
    }
  }, []);

  return <Fragment>{children}</Fragment>;
}

export default withRouter(ScrollToTop);

We call history.listen to listen for navigation.

In the callback for it, we call window.scrollTo(0, 0) to scroll to the top.

It returns a function to clear the listener, so we call that in the function that we return in the useEffect callback.

We pass in an empty array to useEffect to attach the listener only once when the ScrollToTop component is mounted.

Then we can use it by writing;

<Router>
  <ScrollToTop>
    <Switch>
       <Route path="/" exact component={Home} />
    </Switch>
  </ScrollToTop>
</Router>

We wrap ScrollToTop around all our routes so that scrolling to top is done when any route component loads.

React Router and withRouter

withRouter is a component that we can call to let us get the location , history , and match objects as props in our component.

For instance, we can write:

import React from "react";
import PropTypes from "prop-types";
import { withRouter } from "react-router";

class App extends React.Component {
  static propTypes = {
    match: PropTypes.object.isRequired,
    location: PropTypes.object.isRequired,
    history: PropTypes.object.isRequired
  };

  render() {
    const { match, location, history } = this.props;
    return <div>{location.pathname}</div>;
  }
}

const ShowTheLocationWithRouter = withRouter(App);

match is an object that has information about a router’s path.

It has the params property to get the segments of the path.

isExact is true if the path matches the URL.

path is a string with the pattern that’s used to match.

url is a string that has the matched portion of the URL.

location is an object that has the pathname with the pathname.

search is the query string portion of the URL.

hash has the part of the URL after the # sign.

history is the native history object.

It has the length with the number of entries in the history stack.

The location property has the parts of the URL returned as an object.

It’s the same as the location object itself.

push is a method to let us navigate to a new path.

replace lets us navigate to a new path by overwriting history.

go navigate to a history entry by the number of steps.

goBack moves to the previous history.

goFoward lets us go to the path in the next history entry.

React Components from Array of Objects

We can render an array of objects into a list of component by using the map method.

For instance, we can write:

const Items = ({ items }) => (
  <>
    {items.map(item => (
      <div key={items.id}>{items.name}</div>
    ))}
  </>
);

All we do is call map with a callback to return the entries derived from the items entry.

key should have a unique ID so that React can distinguish each entry even if they’ve moved.

Fix Input Losing Focus When Rerendering Problem

This may happen if we create our own input component and we created it within the render method.

This will cause a new instance of our custom input component to be created every time the input is rendered.

Therefore, we should move it out of render .

We can keep the input focused by writing:

import React from 'react';
import styled from 'styled-components';

const Container = styled.div``;
const Input = styled.input``;

class App extends React.Component {
  constructor(){
    this.state = {
      name: ''
    };
    this.updateName = this.updateName.bind(this);
  }

  updateName(e){
    e.preventDefault();
    this.setState({ name: e.target.value });
  }

  render() {
    return (
      <Container>
        <Input
          type="text"
          onChange={this.updateName}
          value={this.state.name}
        />
      </Container>
    )
  }
}

We move the Input and Container outside the App component to create the components outside rather than on the fly inside.

This means that the same instance will always be used.

And the input will stay focused when App rerenders.

Conclusion

We shouldn’t create any components on the fly without our component so that the same instance is always used.

We can create our own component to scroll a component to the top when we navigate to a different route.

withRouter injects a few objects to our component.

Categories
React Tips

React Tips — Infinite Scroll, Submit, Focus, and Drag and Drop

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.

onSubmit in React

To run a submit handler in a React app, we should call preventDefault to prevent the default submit behavior, which is to submit to a server.

For instance, we write:

class App extends React.Component {

  submit(e){
    e.preventDefault();
    alert('submitted');
  }

  render() {
    return (
      <form onSubmit={this.submit}>
        <button type='submit'>click me</button>
      </form>
    );
  }
});

We called e.preventDefault() with the submit method, which we pass as the value of the onSubmit prop.

React onClick Being Called on Render

We’ve to pass in the reference to a function instead of calling it.

For instance, we write:

class Create extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    const playlist = this.renderPlaylists(this.props.playlists);
    return (
      <div>
        {playlist}
      </div>
    )
  }

  renderPlaylists(playlists) {
    const activatePlaylist = this.activatePlaylist.bind(this, playlist.id);
    return playlists.map(playlist => {
      return (
        <div key={playlist.id} onClick{activatePlaylist}>
          {playlist.name}
        </div>
      );
    })
}

We have:

this.activatePlaylist.bind(this, playlist.id)

which returns a function that changes the value of this to the current component.

Also, it passes the playlist.id as the argument to the this.activatePlaylist method.

Making React Component or Element Draggable

To create a draggable component easily, listen to the mousemove, mousedown, and mouseup events

For instance, we can write:

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

const styles = {
  width: "200px",
  height: "200px",
  background: "green",
  display: "flex",
  justifyContent: "center",
  alignItems: "center"
}

const DraggableComponent = () => {
  const [pressed, setPressed] = useState(false)
  const [position, setPosition] = useState({x: 0, y: 0})
  const ref = useRef()

  useEffect(() => {
    if (ref.current) {
      ref.current.style.transform = `translate(${position.x}px, ${position.y}px)`
    }
  }, [position])

  const onMouseMove = (event) => {
    if (pressed) {
      setPosition({
        x: position.x + event.movementX,
        y: position.y + event.movementY
      })
    }
  }

  return (
    <div
      ref={ref}
      style={styles}
      onMouseMove={ onMouseMove }
      onMouseDown={() => setPressed(true)}
      onMouseUp={() => setPressed(false)}>
      <p>drag me</p>
    </div>
  )
}

We have the Draggable component with some props.

We listen to the mousedown and mouseup events to set the pressed state to be false and true respectively.

This will let us dragged if the pressed state is true , which is when we’re dragging.

Then we add a listener for the mousemove event by passing the onMouseMove function to the onMouseMove prop.

Then we set the position in the onMouseMove function.

We set the position by changing the x and y coordinates of the div if pressed is true .

Infinite Scrolling with React

To add infinite scrolling easily with React, we can use the react-infinite-scroller package.

To install it, we run:

npm install react-infinite-scroller

Then we can use it by writing:

import React, { Component } from 'react';
import InfiniteScroll from 'react-infinite-scroller';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      listData: [],
      hasMoreItems: true,
      nextHref: null
    };
    this.fetchData = this.fetchData.bind(this);
  }

  async fetchData(){
    const listData  = await getJobsData();
    this.setState({ listData });
  }

  componentDidMount() {
     this.fetchData();
  }

  render() {
    const loader = <div className="loader">Loading ...</div>;
    const JobItems = this.state.listData.map(job => {
      return (<div>{job.name}</div>);
    });
    return (
      <div className="Jobs">
         <h2>Jobs List</h2>
         <InfiniteScroll
           pageStart={0}
           loadMore={this.fetchData.bind(this)}
           hasMore={this.state.hasMoreItems}
           loader={loader}
         >
            {JobItems}
         </InfiniteScroll>
      </div>
    );
  }
}

We use the InfiniteScroll component to add infinite scrolling to our app.

pageStart is the starting page number.

loadMore is the function to load more data.

hasMore is the state to see if we have more data.

loader is the loader component.

We get new data every time we load and scroll to the bottom of the page.

Select All Text in Input with React When it’s Focused

We can call the select method on the input to focus it.

For instance, we can write:

const Input = (props) => {
  const handleFocus = (event) => event.target.select();

  return <input type="text" value="something" onFocus={handleFocus} />
}

We have the handleFocus function that calls the select method on the input element to select the input value when it’s focused.

With a class component, we can write:

class Input extends React.Component {
  constructor(){
    super();
    this.handleFocus = this.handleFocus.bind(this);
  }

  handleFocus(event){
    event.target.select();
  }

  render() {
    return (
      <input type="text" value="something" onFocus={this.handleFocus} />
        );
    }
}

We have the handleFocus method to call select to select the input value when we focus the input.

Conclusion

We can use a package to add infinite scrolling easily.

Also, we can select the values of the input.

We can add a draggable item to our component without a library.

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

Categories
React Tips

React Tips — Conditional Prop Validation, and React Router Basics

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.

Set isRequired on a Prop if Another Prop is null or Empty with Prop-Types

Prop-types lets us validate another prop with custom validation.

For instance, we can write:

import PropTypes from 'prop-types';

//...

Item.propTypes = {
  showDelete: PropTypes.bool,
  handleDelete: (props, propName, componentName) => {
    if (props.showDelete === true && typeof props[propName] !== 'function') {
      return new Error('handleDelete must be a function');
    }
  },
}

We have the Item component where we set the propTypes property to do some validation.

We have showDelete set to a boolean prop.

And handleDelete is validated by a function that checks if the showDelete prop is true and that the handleDelete prop is a function.

propName is the name of the prop that we’re currently validating.

So propName is the handleDelete prop.

We make sure that if props.showDelete is true , the handleDelete prop is a function.

There’s also the react-required-if package that lets us simplify our code.

For instance, we can write:

import requiredIf from 'react-required-if';
import PropTypes from 'prop-types';

//...

Item.propTypes = {
  showDelete: PropTypes.bool,
  handleDelete: requiredIf(PropTypes.func, props => props.showDelete === true)
};

We make sure that handleDelete is a function when showDelete is true with the requiredIf function.

Wrong Components in a List Rendered by React

If we’re rendering a list of items, we should assign a unique value for the key prop to each item in the list.

For instance, we can write:

<div>
  <div className="packages">
    <div key={0}>
      <button>X</button>
      <Package name="a" />
    </div>
    <div key={1}>
      <button>X</button>
      <Package name="b" />
    </div>
    <div key={2}>
      <button>X</button>
      <Package name="c" />
    </div>
  </div>
</div>

We have a list of items, and we assigned a unique value for each key prop.

This way, they’ll be rendered properly no matter what we do with them.

If we’re rendering an item, we should write:

consr packages = this.state.packages.map((package, i) => {
  return (
    <div key={package}>
      <button onClick={this.removePackage.bind(this, package)}>X</button>
      <Package name={package.name} />
    </div>
  );
});

We make sure that we pass in a unique value for the key prop.

Then when we manipulate the array and re-render it, everything will be rendered properly.

We should never use the array index as the key since they can change and may not be unique.

How to Create an App with Multiple Pages using React

To let us create an app that has multiple pages in React, we’ve to use React Router to do the routing.

We install it by running:

npm install react-router-dom

Then we write:

import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";

const Home = () => {
  return <h2>Home</h2>;
}

const About = () => {
  return <h2>About</h2>;
}

const Profile = () => {
  return <h2>Profile</h2>;
}

export default function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/profile">Profile</Link>
            </li>
          </ul>
        </nav>

        <Switch>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/profile">
            <Profile />
          </Route>
          <Route path="/">
            <Home />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

We created 3 function components which we use as the route’s content.

Then in the App component, we import the Switch component and add the routes inside.

The Route component lets us create the routes.

path is the URL path that we want to map to the component.

And we add the component we want to display inside the Route component.

Link is provided by React Router so that we go to the URL that we want to go to.

It can also work with nested routes, custom links, default routes, query strings, and URL parameters.

We can add nestyed routes by writing:

loads the Topics component, which renders any further <Route>'s conditionally on the paths :id value.import React from "react";
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link,
  useRouteMatch,
  useParams
} from "react-router-dom";

export default function App() {
  return (
    <Router>
      <div>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about">About</Link>
          </li>
          <li>
            <Link to="/topics">Topics</Link>
          </li>
        </ul>

        <Switch>
          <Route path="/topics">
            <Topics />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

function Topics() {
  let match = useRouteMatch();

  return (
    <div>
      <h2>Topics</h2>

      <ul>
        <li>
          <Link to='about'>About</Link>
        </li>
      </ul>

     <Switch>
        <Route path='/about' >
          <About />
        </Route>
      </Switch>
    </div>
  );
}

function About() {
  return <h2>About</h2>;
}

We just nest routes in components to nest them.

Conclusion

We create an app that has multiple pages with React Router.

Also, we can conditionally validate props with a function or a 3rd party library.

And we should always add a key prop with a unique value to each list item.

Categories
React Tips

React Tips — JWT and Redux, Run Code After setState and set Body Styles

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.

setState is One Step Behind onChange

To make sure that we set our state sequentially within a React component, we can pass in a callback as a 2nd argument of setState .

The callback is run when the value in the first argument is set as the new state value.

For instance, we can write:

handleChange(e) {
  this.setState({ name: e.target.value }, this.handleSubmit);
}

We update the name state with our inputted value.

And then we call the handleSubmit method, which is a method that’s called after the name state is set.

In function components, we can write:

useEffect(() => {
  //...
}, [name]);

to run the callback when the name state changes.

How to Sync Props to State using React Hooks

To sync prop values to state in a function component, we can use the useEffect hook to watch for prop value changes.

Then the callback we pass into the hook is run and when the prop value changes.

For instance, we can write:

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

const Persons = ({ name }) =>  {
  const [nameState , setNameState] = useState(name);

  useEffect(() => {
    setNameState(name);
  }, [name])

  return (
    <div>
       <p>My name is {props.name}</p>
       <p>My name is {nameState}</p>
    </div>
  )
}

We have the Persons component that takes a name prop.

We set the initial state with the useState hook by passing in our prop value to it.

Then we added a useEffect hook to listen to the name value for changes.

If it changes, the callback is run.

We call setNameState to update the nameState with the latest name value.

Then we display both the prop and the state value.

Use Redux to Refresh a JSON Web Token

To use redux to refresh a JSON web token, we’ve to create a thunk and use the Redux thunk middleware.

To do that, we can write:

import { createStore, applyMiddleware, combineReducers } from 'redux';
import thunk from 'redux-thunk';
import { reducer } from './reducer';

const rootReducer = combineReducers({
  reducer
  //...
})
const store = createStore(rootReducer, applyMiddleware(thunk));

to apply the thunk middleware in our store.

Then we can create our reducer by witing:

reducer.js

const initialState = {
  fetching: false,
};

export function reducer(state = initialState, action) {
  switch(action.type) {
    case 'LOAD_FETCHING':
      return {
        ...state,
        fetching: action.fetching,
      }
   }
}

We have a reducer that stores the fetching state.

Then we can create our think by writing:

export function loadData() {
  return (dispatch, getState) => {
    const { auth, isLoading } = getState();
    if (!isExpired(auth.token)) {
      dispatch({ type: 'LOAD_FETCHING', fetching: false })
      dispatch(loadProfile());
    } else {
      dispatch({ type: 'LOAD_FETCHING', fetching: true })
      dispatch(refreshToken());
    }
  };
}

We created a thunk that calls dispatch and also gets the state to check if we need to get the token with the refresh token.

A thunk returns a function with the dispatch function to dispatch actions and getState to get the state.

And then we can dispatch the thunk by writing:

componentDidMount() {
  dispath(loadData());
}

in our component.

There’s also the redux-api-middleware package that we can add as a middleware to our React app.

We can install it by running:

npm i redux-api-middleware

Then we can create an action with it by writing:

import { createAction } from `redux-api-middleware`;

const getToken = () => createAction({
  endpoint: 'http://www.example.com/api/token',
  method: 'GET',
  types: ['REQUEST', 'SUCCESS', 'FAILURE']
})

export { getToken };

type is a string that tells what action has occurred.

We also pass in the endpoint with the URL, and method with the request method.

We can add the middleware by writing:

import { createStore, applyMiddleware, combineReducers } from 'redux';
import { apiMiddleware } from 'redux-api-middleware';
import reducers from './reducers';

const reducer = combineReducers(reducers);
const createStoreWithMiddleware = applyMiddleware(apiMiddleware)(createStore);

export default function configureStore(initialState) {
  return createStoreWithMiddleware(reducer, initialState);
}

We import the reducers and the middleware and incorporate them into our store.

Then we can use the action that we created with createAction .

Conclusion

There are several ways to get a token with Redux.

Also, we can run code after setState is done.

And we can watch for prop value changes and update the state accordingly.