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.

Categories
React Tips

React Tips — HTML, State Arrays, and Images

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 Pass HTML Tags in Props

There are several ways to pass HTML tags as props.

One way is to pass JSX expressions as props.

For instance, we can write:

myProp={<div><Foo />Some String</div>}

We can also pass in an HTML string:

myProp="<div>This is some html</div>"

Then we can render it as HTML by writing:

<div dangerouslySetInnerHTML={{ __html: this.props.myProp }}></div>

We set the dangerouslySetInnerHTML prop to render HTML as-is.

It only works with simple HTML and not JSX expressions, components, or other things.

We can also pass in an array of JSX elements:

myProp={["foo", <span>Some other</span>, "bar"]}

We have both strings and HTML in our myProp array.

We can then render this array the way we want.

Also, we can pass in components as the children of another component.

For instance, we can write:

<Foo>
  <div>Some content</div>
  <div>Some content</div>
</Foo>

We have the Foo component that’s wrapped around 2 divs.

In Foo we can render the components inside by referencing this.props.children for class components.

And in function components, we get the children property from the props parameter, which is the first one.

We can also use a fragment:

<MyComponent myProp={<React.Fragment>This is an <b>HTML</b> string.</React.Fragment>} />

Then we can pass in multiple elements without rendering a wrapper.

Implement Authenticated Routes in React Router

We can implement authenticated routes with our own components.

For instance, we can write:

const PrivateRoute = ({ component: Component, authed, ...rest }) => {
  return (
    <Route
      {...rest}
      render={(props) => authed
        ? <Component {...props} />
        : <Redirect to={{pathname: '/login', state: {from: props.location}}} />}
    />
  )
}

We created our own PrivateRouter component that takes the component that we want to protect.

We renamed the component prop to Component to make it uppercase.

Then we render the component if authentication credentials are valid.

Otherwise, we return the Redirect component to redirect to an unprotected page.

Then we can use it by writing:

<PrivateRoute authed={this.state.authed} path='/profile' component={Profile} />

We pass in the component that we want into PrivateRouter to protect it.

React.cloneElement vs this.props.children

We need to use React.cloneElement if we need to do anything other than rendering the children components.

This is because this.prop.children is only a descriptor of the children.

For instance, if we have the following:

render() {
  return(
    <Parent>
      <Child>First</Child>
      <Child>Second</Child>
      <Child>Third</Child>
    </Parent>
  )
}

Then to add a prop to it, we need to write:

render() {
  return (
    <div>
      {React.Children.map(this.props.children, child => {
        return React.cloneElement(child, {
          onClick: this.props.onClick })
      })}
    </div>
  )
}

We’ve to call React.cloneElement to make a clone of each child to add an onClick handler to each child component.

Push into State Array

We can puts into a state array by concatenating the new entries to it.

This way, we don’t mutate the original array.

We don’t want to change the original since it’ll be overwritten on the next render.

For instance, we can write:

const arr = this.state.myArray.concat('new');
this.setState({ myArray: arr })

We can also use the spread operator:

this.setState({ myArray: [...this.state.myArray, 'new'] })
this.setState({ myArray: [...this.state.myArray, ...[1,2,3] ] })

The first one adds a single entry as we have above.

The 2nd merged the 2nd array into the first one and return it.

If we need to set the new array value based on the current array’s value, we can call setState with a callback that returns a new array based on the previous one.

For instance, we can write:

this.setState(prevState => ({
  myArray: [...prevState.myArray, "new"]
}))

We return the state with a new array.

Load Local Images with React

We can load local images by importing the image as a module.

For instance, we can write:

import React from 'react';
import logo from './logo.png';

function Header() {
  return <img src={logo} alt="Logo" />;
}

We import the image as a module and we put it straight into the src prop.

We can also do the same with require :

<img src={require('./logo.png')} />

Conclusion

We can add images by importing them.

There are several ways to pass HTML as props.

React.cloneElement is required for adding props to children.

There are several ways to push new data to a state array.

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.