Categories
React Tips

React Tips — Testing, Redirects, and Markdown

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 with Redirect Component with React Router

We can pass props with React Router’s Redirect component by passing in the state value.

For instance, we can write:

<Redirect
  to={{
    pathname: '/order',
    state: { id: '123' }
  }}
/>

We pass in the pathname for the URL path.

And the state has the state we want to pass to the component.

And then we can write:

this.props.location.state.id

to get the id in the component.

Distinguish Left and Right Click Events with React

We can distinguish between left and right-click by checking the type property of the event object.

For instance, if we have:

return <p onClick={this.handleClick} onContextMenu={this.handleClick}>click me</p>

Then we can write:

handleClick(e) {
  if (e.type === 'click') {
    console.log('Left click');
  } else if (e.type === 'contextmenu') {
    console.log('Right click');
  }
}

This is detecting a synthetic event.

We can also detect left and right click with nativeEvent :

handleClick(e) {
  if (e.nativeEvent.which === 1) {
    console.log('Left click');
  } else if (e.nativeEvent.which === 3) {
    console.log('Right click');
  }
}

The which property has the click type.

1 is left click and 3 is for right-click.

Using Jest to Spy on Method Call in componentDidMount

We can use the spyOn method to check which component method is called.

for instance, we can write:

const spy = jest.spyOn(Component.prototype, 'someMethod');
const wrapper = mount(<Component {...props} />);
wrapper.instance().someMethod();
expect(spy).toHaveBeenCalled();

Component is the component we’re testing.

someMethod is the method we’re spying.

We mount the component and get the instance with the instance method.

someMethod is the method we called.

Then spy should be called.

And then we clear our spies with:

afterEach(() => {
  spy.mockClear()
})

after each test.

How to Capture Only Parent’s Click Event and not Children

We should call preventDefault to capture only the parent component’s click event and not the children’s.

For instance, we can write:

onParentClick(event) {
  event.preventDefault();
  console.log(event.currentTarget);
}

How to Render Markdown from a React Component

We can render markdown with the react-markdown library.

For instance, we can write:

import React from 'react'
import Markdown from 'react-markdown'

const code = "# header";

React.render(
  <Markdown source={code} />,
  document.getElementById('root')
);

We get the Markdown component form the package.

And then we pass in the code to the source prop to render it.

Also, we can convert it to HTML and then render than with dangerousSetInnerHTML with the marked library.

For instance, we can write:

import React from 'react';
import marked from 'marked';

class Markdown extends React.Component {
  constructor(props) {
    super(props);

    marked.setOptions({
      gfm: true,
      tables: true,
      breaks: false,
      pedantic: false,
      sanitize: true,
      smartLists: true,
      smartypants: false
    });
  }
  render() {
    const { text } = this.props,
    html = marked(text || '');

    return (
      <div>
        <div dangerouslySetInnerHTML={{__html: html}} />
      </div>
    );
  }
}

Markdown.propTypes = {
  text: React.PropTypes.string.isRequired
};

Markdown.defaultProps = {
  text: ''
};

We set the options with the setOptions method.

gfm means we render Github flavored Markdown.

tables means we render tables.

breaks mean we render line breaks with br.

pedantic means we conform to the original Markdown spec and don’t fix their bugs or behavior.

sanitize we sanitize the HTML.

smartLists uses the smartlist behavior of the Markdown spec.

smartypants means using smart typographic punctuation for things like quotes and slashes.

Testing with Jest Using Date Objects Produce Different Snapshots in Different Timezones

We can set the current time to be a constant time in Jest.

For instance, we can write:

Date.now = jest.fn(() => new Date(Date.UTC(2020, 7, 9, 8)).valueOf())

Then we can set the timezone when we run our tests.

In Mac and Linux, we add:

"test": "TZ=America/Los_Angeles react-scripts test --env=jsdom",

And in Windows, we add:

"test": "set TZ=America/Los_Angeles && react-scripts test --env=jsdom",

to package.json ‘s scripts section.

Conclusion

We can pass states to the Redirect component.

Also, we can set the time zone for the and date for Jest tests.

We can also spy on function calls with them.

We can also capture left and right clicks and clicks from parent elements only.

There are various ways to render Markdown in our React component.

Categories
React Tips

React Tips — Scroll to Top When Navigating

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.

Return Multiple Lines JSX in Another Return Statement in React

We can return multiple lines of JSX code in when we map them from an array by returning an array in the map callback.

For instance, we can write:

render() {
  return (
    {[1, 2, 3].map((n) => {
      return [
        <h3>Item {n}</h3>
        <p>{n}</p>
      ]
    }}
  );
}

We can also return a fragment to wrap around the components:

render() {
  return (
    {[1, 2, 3].map((n, index) => {
      return (
        <React.Fragment key={index}>
          <h3>Item {n}</h3>
          <p>{n}</p>
        </React.Fragment>
      )
    }}
  );
}

Get History on react-router

We can get the history with React Royer by calling the createBrowserHistory method.

For instance,e we can write:

import { Router } from 'react-router-dom'
import { createBrowserHistory } from 'history'
import App from './App'

const history = createBrowserHistory({
  //...
});

ReactDOM.render((
  <Router history={history}>
    <App />
  </Router>
), holder)

We can also use the withRouter higher-order component to inject the history object into a component.

For instance, we can write:

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

class App extends React.Component {
  render () {
    this.props.history;
  }
}

withRouter(App);

We called withRouter with App to inject the history prop to it.

Then in our App component, we can get the history with this.props.history .

Include a Font Awesome Icon in React’s render()

To include Font Awesome icons in our React app, we can install the package by running:

npm install --save font-awesome

Then we can include the bundled CSS by writing:

import '../node_modules/font-awesome/css/font-awesome.min.css';

or:

import 'font-awesome/css/font-awesome.min.css';

And then in our component, we write:

render() {
    return <div><i className="fa fa-spinner fa-spin"></i></div>;
}

We set the class names for the icon as the value of the className prop.

There’s also the react-fontawesome package that lets us use icons by including the them bundled React components in our components.

To install it, we run:

npm install --save react-fontawesome

Then we import it by adding:

const FontAwesome = require('react-fontawesome');

Then we can use it by writing:

class App extends React.Component {
  render() {
    return (
      <FontAwesome
        name='rocket'
        size='2x'
        spin
        style={{ textShadow: '0 1px 0 rgba(0, 0, 0, 0.1)' }}
      />
    );
  }
});

We use the FontAwesome component to add the icon.

React Router Scroll to Top on Every Transition

We can create our own component to scroll to the top and wrap that around the component that we want to scroll to the top.

For instance, we can write:

class ScrollToTop extends Component {
  componentDidUpdate(prevProps) {
    if (this.props.location !== prevProps.location) {
      window.scrollTo(0, 0)
    }
  }

  render() {
    return this.props.children
  }
}

export default withRouter(ScrollToTop)

We call the withRouter prop with the ScrollToTop component.

Then we have the location prop available in ScrollToTop after that.

In the component, we check the location prop to see what the path is in the componentDidUpdate method.

If they’re different, that means we transitioned to a new route.

So we call window.scrollTo(0, 0) to scroll to the top of the page.

In render , we render the children prop so that we display the content of it.

Then, to use it, we write:

import ScrollToTop from './ScrollToTop';

//...

const App = () => (
  <Router>
    <ScrollToTop>
      <Foo />
    </ScrollToTop>
  </Router>
)

We wrap it our around Foo component to scroll it to the top when it’s loaded.

Also, we can do the same thing with hooks.

For instance, we can write:

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

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

  return null;
}

export default withRouter(ScrollToTop);

We use withRouter again so that we get the history prop.

But we call history.listen instead of checking the value of history .

We call window.scrollTo(0, 0) whenever the callback of history.listen runs.

It returns a function to remove the listen.

So we put that into the function that’s returned in the useEffect callback.

We pass in an empty array as the 2nd argument of useEffect to only load the callback when the component mounts.

Then we use it by writing:

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

Conclusion

There are several ways to scroll to the top when we navigate to a different route.

We can return multiple components with map in an array.

Categories
React Tips

React Tips — Force Render, Conditionals, Listen for Navigation

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 Force a Function Component to Render

We can force a function component to render with the use-force-update package.

To install it, we run:

npm install use-force-update

or:

yarn add use-force-update

Then we can use it by writing:

import useForceUpdate from 'use-force-update';

const App = () => {
  const forceUpdate = useForceUpdate();

  const rerender = () => {
    console('rerendering');
    forceUpdate();
  };

  return <button onClick={rerender} />;
};

We get the useForceUpdate hook to return the forceUpdate function that lets us update whenever we want.

Also, we can set a state to make a React component update.

For instance, we can write:

import React, { useState } from 'react';

function useForceUpdate(){
  const [value, setValue] = useState(0);
  return () => setValue(value => ++value);
}

function App() {
  const forceUpdate = useForceUpdate();

  return (
    <div>
      <button onClick={forceUpdate}>
        re-render
      </button>
    </div>
  );
}

We created our own useForceUpdate hook to update a value state.

The useState hook returns a state variable and a function to update it.

Whenever we update a state, React will render the component again.

componentDidMount Equivalent in a React Function Component

The equivalent of componentDidMount in a function component is the useEffect hook with an empty array.

For instance, we can write:

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

to make the code in the callback only load when the component mounts.

We can also pass in variables to the array to watch those values for changes:

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

The content can be any value like states, props, etc.

Detect Route Change with React Router

We can detect route change with React Router with the history.listen method.

For instance, we can write:

history.listen((location, action) => {
  console.log(location, action);
})

location is the native location object that has all the URL data like the pathname for the pathname.

search for the query string.

hash for the string after the hash.

action has the name for the navigation action.

Setting State on componentDidMount()

Setting state in the componentDidMount method isn’t an antipattern.

It’s a recommended practice for setting state when the component mounts.

For instance, we can use it to get API data and set the state:

componentDidMount() {
  fetch("https://randomuser.me/api")
    .then(res => res.json())
    .then(
      (result) => {
        this.setState({
          isLoaded: true,
          user: results[0]
        });
      },
      (error) => {
        this.setState({
          isLoaded: true,
          error
        });
      }
    )
}

We get the data from an API with the fetch API.

Then we get the resulting data in the first then callback to set the state for the data.

In the 2nd callback, we set the isLoaded state to false and an error state.

Use if…else… Statement in React render Function

There are a few ways to display things conditionally with React.

We can use various boolean expressions to do so.

For example, we can write:

render() {
  const { isLoggedIn } = this.state;
  return (
    <div>
      {isLoggedIn ? (
        <LogoutButton onClick={this.handleClick} />
      ) : (
        <LoginButton onClick={this.handleClick} />
      )}
    </div>
  );
}

We get the isLoggedIn state and use that to check the if the user is logged in.

If the user isn’t then we return LogoutButton .

Otherwise, we return LoginButton .

We can also use an if-else statement to assign a component to a variable/

For instance, we can write:

render() {
  let button;
  if (isLoggedIn) {
    button = <LogoutButton onClick={this.handleClick} />;
  } else {
    button = <LoginButton onClick={this.handleClick} />;
  }

  return (
    <div>
      {button}
    </div>
  );
}

We check isLoggedIn with an if-else statement instead of a ternary expression.

We assigned our components to the button variable and render that instead of writing everything inline.

This lets us write longer expressions in a conditional statement.

Also, we can use the && operator to display things given a condition.

For example, we can write:

render() {
  return (
    <div>
      {cartItems.length > 0 &&
        <h2>
          You have {cartItems.length} in the cart.
        </h2>
      }
    </div>
  );
}

If cartItems.length > 0 is true then the stuff that comes after it is rendered.

Conclusion

We can force a component to render in various ways.

Also, we can display things conditionally with several kinds of statements and expressions.

And we can use history.listen to listen for changes in React Router.

Categories
React Tips

React Tips — Redirect, Error Handling and Redux, and .env Files

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 Button Redirect Page on Click

We can redirect to a page when we click on an element by getting the history object.

For instance, we can write:

import React from 'react';
import { useHistory } from "react-router-dom";
function LoginPage () {
  const history = useHistory();
  const onClick = () => {
    history.push('new-page');
  }

  return (
    <div>
      <button
        onClick={onClick}
      >
        Login
      </button>
    </div>
  );
}
export default LoginPage;

We get the native history object with useHistory

Then we define the onClick function to call history.push to navigate to a new page.

If we’re using class components, we can write:

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

class LoginPage extends Component {
  constuctor() {
    this.routeChange = this.routeChange.bind(this);
  }

  onClick() {
    this.props.history.push('forgot-password');
  }

  render() {
    return (
      <div>
        <button onClick={onClick}>Forgot password?</button>
      </div>
    );
  }
}

export default withRouter(LoginPage);

We have the LoginPage class component.

To make the history prop available to the component, we pass it to withRouter .

We have the onClick method that calls the this.props.history.push method to navigate to the new page.

The routerChange method has to be bound to the component with bind so that we set the component class as the value of this .

Render Boolean Value in JSX

We can render boolean value in JSX by converting it to a string first.

For instance, we can write:

Boolean Value: {bool.toString()}

or:

Boolean Value: {String(bool)}

or:

Boolean Value: {'' + bool}

or:

{`Boolean Value: ${bool}`}

or:

Boolean Value: {JSON.stringify(bool)}

There are many ways to convert a boolean value into a string.

They’re all good except for the concatenation, which may be confusing.

Using event.target with React Components

We can use event.target to get a DOM element’s properties.

We can use the dataset property to get attributes prefixed with the data- prefix.

They’re considered custom attributes that let us pass data around with an element.

For instance, if we have a button, then we can write:

<button
  data-foo="home"
  data-bar="home"
  onClick={this.props.onClick}
/>
  Button
</button>

Then we can write:

onClick(e) {
   console.log(e.target.dataset.bar, e.target.dataset.foo);
}

to get the foo and bar properties from the button that we clicked with the dataset property.

dataset.foo has the value of the data-foo attribute.

dataset.bar has the value of the data-bar attribute.

Adding a .env File to React Project

If we have a create-react-app project, we can add an .env file to add the environment variables.

Inside the file, any keys that are prefixed with the REACT_APP_ prefix are read into the app.

So in our .env file, we can write:

REACT_APP_API_KEY=secret

We can then use the environment variable values by writing:

fetchData() {
  fetch(`https://example.com?api-key=${process.env.REACT_APP_API_KEY}`)
    .then((res) => res.json())
    .then((data) => console.log(data))
}

We read the environment variable value with the process.env object.

How to Pass Multiple Parameters to Input’s onChange Handler

We can pass in multiple parameters to an input’s onChange handler.

To do that, we can write:

<Input
  type="text"
  value={this.state.name}
  onChange={this.onChange.bind(this, this.state.user.id)}
/>

Then we can define our onChange method by writing:

onChange(`userId`, event) {
  const newName = event.target.value;
},

We have whatever we pass in as the first argument.

And the last argument is the object.

How to Catch and Handle Error Response 422 with Redux and Axios

We can call dispatch to dispatch the action within a React component.

For instance, we can write:

axios({
  method: 'post',
  responseType: 'json',
  url: `${SERVER_URL}/login`,
  data: {
    username,
    password
  }
})
 .then(response => {
   dispatch(setUser(response));
 })
 .catch(error => {
   dispatch({ type: AUTH_FAILED });
   dispatch({ type: ERROR, payload: error.data.error.message });
 });

We make a POST request with Axios.

Then in the then callback, we get the response and call dispatch and our setUser action creator.

And then we call the catch method with a callback to handle errors.

We call dispatch with or without a payload.

Calling dispatch would update the store with the new state value.

Conclusion

We can redirect pages on click.

And we can handle errors with Redux by calling dispatch to update the stores.

Booleans can be rendered if we convert them to a string.

Categories
React Tips

React Tips — Loading Data, Redux Stores, and Styled Links

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 on Parent Inside Child Component

We can pass a function from the parent to the child component.

Then we can call it inside the child to set the state if the parent.

For instance, we can write:

import React, { useState, useEffect, useCallback, useRef } from "react";

function Parent() {
  const [parentState, setParentState] = useState(0);

  const wrapperSetParentState = useCallback(val => {
    setParentState(val);
  }, [setParentState]);

  return (
    <div>
      <Child
        setParentState={wrapperSetParentState}
      />
      <div>{parentState}</div>
    </div>
  );
};

function Child({ setParentState }) {
  const [childState, setChildState] = useState(0);

  useEffect(() => {
    setParentState(childState);
  }, [setParentState, childState]);

  const onSliderChange = e => {
    setChildState(e.target.value);
  };

  return (
    <div>
      <input
        type="range"
        min="1"
        max="100"
        value={childState}
        onChange={onSliderChange}
      ></input>
    </div>
  );
};

We created the Child component with a slider input that takes a range of values.

Also, we defined the onSliderChange function into the onChange prop to watch for changes.

We set the e.target.value , which has the slider’s value as the value of the childState.

We also watch the changes for the childState to watch for changes for it.

And we called setParentState to call the function from the Parent that we passed into the props.

It set’s the parentState value from the parent,

We then display the latest value of the parentState in Parent .

useCallback lets us cache the value of parentState if it hasn’t changed.

React Router v4 <NavLink> vs <Link>

NavLink adds an active class to the link when it’s navigated to so that we can style it differently from the other links.

It takes an activeClassName prop to let us change the class name.

For instance, we can write:

<NavLink to="/" activeClassName="active">profile</NavLink>

We can make the dynamic to style the link the way we want.

React Render String with Non-Breaking Spaces

We can style the white-space: nowrap style to display strings with non-breaking spaces.

For instance, we can write:

<div style="white-space: nowrap">no breaks</div>

or

<div style={{ whiteSpace: 'nowrap' }}>no breaks</div>

React Async Rendering of Components

We can render async data by providing a loading message that’s displayed when something is loading.

If there’s data, then we display that instead of the loading message.

For instance, we can write:

import React from 'react';

class App extends React.PureComponent {
  constructor(props){
    super(props);
    this.state = {
      data: null
    }
  }

  componentDidMount(){
    fetch('https://randomuser.me/api')
      .then((resp) => resp.json())
      .then((response) => {
        const [data] = response.results;
        setState({ data });
      });
    }

  render(){
    return (<div>
      {this.state.data === null ?
        <div>Loading</div>:
        <div>{this.state.data.name.first}</div>
      }
    </div>);
  }
}

We display a loading message when the data state is null .

Otherwise, we show the data that we want to display from the API.

We fetch the data in componentDidMount , which means that the data will be fetched when the component mounts.

Dispatch Action on App Load with React-Redux

We can call mapStateToProps to map the states from the Redux stores as props of a component.

mapDispatchToProps match the action dispatch functions to props of a component.

For instance, we can write:

class App extends Component {
  componentDidMount() {
    this.props.getUser()
  }

  render() {
    return this.props.isReady
      ? <div> ready </div>
      : <div>not ready</div>
  }
}

const mapStateToProps = (state) => ({
  isReady: state.isReady,
})

const mapDispatchToProps = dispatch => {
  return {
    getUser: () => dispatch(getUserActionCreator())
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(App)

We create a mapStateToProps function that takes a state parameter, which has the state parameter with the Redux state.

Then we can get the isReady state from it and map it to the isReady prop in the key.

getUser is mapped to a function that calls dispatch to dispatch an action.

getUseractionCreator returns an object that has the type and payload properties to pass those to the reducer and run the right action.

With function components, we can write:

import { appInit } from '../store/actions';
import { useDispatch } from 'react-redux';

const appInit = () => ({ type: APP_INIT });

export default App() {
  const dispatch = useDispatch();
  useEffect(() => dispatch(appInit()), [ dispatch ]);

  return (<div>something</div>);
}

We call the useDispatch hook to let us dispatch actions returned from the appInit function, which also has the type and payload properties.

Conclusion

We can dispatch actions with React-Redux to manipulate the store.

Also, we can call parent component’s functions in a child component.

Different things can be rendered our way when we load data.