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.

Categories
React Tips

React Tips — Get Data, Check Scrolling, and Way Use React Router Properly

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.

‘You should not use Route or withRouter() outside a Router when using react-router 4’ Error with the styled-components Library

To fix this error, we should make sure that we wrap the BrowserRouter component around our app.

For instance, we can write:

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

ReactDOM.render(
   <BrowserRouter>
     <App />
   </BrowserRouter>
, document.getElementById('root'));

Listening to Window Events from Components

We can listen to events by attach event listeners in the componentDidMount method.

Then the listener is added when the component mounts.

We can remove the listen with removeEventListener in the componentWillUnmount to clean it up.

For instance, we can write:

class Home extends Component {
  constructor(props) {
    super(props)
    this.handleScroll = this.handleScroll.bind(this);
  }

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

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

  handleScroll(e) {
    console.log('scrolled');
    console.log(e);
  }

  render() {
    return (
     <div>
       <Foo />
       <Bar />
       <Baz />
     </div>
    );
  }
}

We added the scroll event listener in compoonentDidMount .

The handler is the this.handleScroll method.

Then we have the removeEventListener method call within componentWillUnmount .

“Using string literals in ref attributes is deprecated (react/no-string-refs)” Lint Warning

We shouldn’t be using string refs since they’re being deprecated.

Instead, we can use createRef or callback refs.

For instance, we can write:

class App extends Component {
  constructor() {
    super();
    this.btnRef = React.createRef();
    this.handleClick = this.handleClick.bind(this);
  }

  render() {
    return (
      <div>
        <button ref={this.btnRef} onClick={this.handleClick}>click me</button>
      </div>
    );
  }
}

The ref is created with createRef .

We assigned the ref to the button with the ref prop.

Also, we can assign a ref with a callback as follows:

class App extends Component {
  constructor() {
    super();
    this.btnRef;
    this.state = { clicked: false };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(){
    //...
  }

  render() {
    return (
      <div>
        <button ref={(el) => this.btnRef = el} onClick={this.handleClick}>click me</button>
      </div>
    );
  }
}

We get the element with the el parameter and then set it to this.btnRef .

Set State of Response from Axios in React

We can set the state inside the callback.

For instance, we can write:

axios.get('/url')
 .then((response) => {
   this.setState({ events: response.data })
 })
.catch(function (error) {
   console.log(error);
});

We make a GET request to a URL, then call setState on it.

We’ve to use an arrow function so that we can access the correct this , which is the component itself.

A full example would be the following:

import React from 'react';
import axios from 'axios';
export default class App extends React.Component {
  state = {
    persons: []
  }

  componentDidMount() {
    axios.get(`https://jsonplaceholder.typicode.com/users`)
      .then(({ data }) => {
        const persons = data;
        this.setState({ persons });
      })
  }

  render() {
    return (
      <div>
        { this.state.persons.map(person => <p>{person.name}</p>)}
      </div>
    )
  }
}

We make the same request and get the data from the data property of the response,

Then we call setState to update the persons state.

In the render method, we render the persons state array into paragraphs.

Detecting When User Scrolls to Bottom of div with React

We can listen for scroll events.

In the scroll event handler, we can get the getBoundClientRect method’s bottom property and compare it to the window.innerHeight to see of the div is at the bottom of the div.

For instance, we can write:

class App extends Component {
  constructor(props) {
    super(props);
    this.headerRef = React.createRef();
  }

  isBottom(el) {
    return el.getBoundingClientRect().bottom <= window.innerHeight;
  }

  componentDidMount() {
    document.addEventListener('scroll', this.trackScrolling);
  }

  componentWillUnmount() {
    document.removeEventListener('scroll', this.trackScrolling);
  }

  trackScrolling(){
    if (this.isBottom(headerRef)) {
      document.removeEventListener('scroll', this.trackScrolling);
    }
  };

  render() {
    return (
      <div ref={this.headerRef}>
        ...
      </div>
    }
  }
}

We create the ref with the createRef in the constructor,.

Then in componentDidMount , we listen to the scroll event.

We added the trackScrolling method to listen to the scroll event.

Then we check is we scrolled to the bottom of the div with getBoundingClientRect ‘s returned object to check if we scrolled to the bottom of the div.

Conclusion

There are various ways to check for scrolling.

Also, we shouldn’t use string refs.

And can get data from Axios and set the state to render the data.

Categories
React Tips

React Tips — External URLs, Timers, and Hover Effect

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.

Wait for setState to Finish Before Triggering a Function

We can wait for setState to finish before triggering a function by passing in a function as a 2nd argument of setState .

For instance, we can write:

this.setState({
  firstName,
  lastName,
  age
}, () => {
  console.log(this.state) ;
})

We called setState with the object with the states first.

Then we run our callback to get the latest value of this.state .

External Link with React Router

We can add an external link by passing in a component to redirect to an external link.

For instance, we can write:

<Route path='/external-site' >
  {() => {
     useEffect(() => {
       window.location.href = 'https://example.com';
     }, [])
     return null;
  }}
</Route>

We used the Router component with the path prop to set the path.

Then in our component, we redirect to an external URL by setting the URL as the value of window.location.href .

And we return null to render nothing.

We can also redirect directly in componentDidMount :

class RedirectPage extends React.Component {
  componentDidMount(){
    window.location.replace('http://www.example.com')
  }

  render(){
    return null;
  }
}

Access a Hover State in React

We can set the hove state by listening to the mouseenter and mouseleave events.

For instance, we can write:

<div
  onMouseEnter={this.onMouseEnter}
  onMouseLeave={this.onMouseLeave}
>
  foo
</div>

We can pass in event handlers to the onMouseEnter and onMouseLeave props.

Then we can run code within those methods to set the hover state.

PropTypes in Functional Stateless Component

We can set the prop types in the functional stateless component.

For instance, we can write:

import React from "react";
import PropTypes from "prop-types";

const Name = ({ name }) => <div>hi {name}</div>;

Name.propTypes = {
  name: PropTypes.string
};

Name.defaultProps = {
  name: "james"
};

We created the Name component with the propTypes property.

Then we set the data type of the name prop with it.

We can also set the default value for the name prop.

We’ve to install the propt-types package to set types for the props.

setTimeout() in React Components

We can use setTimeout in React components by calling setTimeout in componentDidMount and then clearing the timer within the componentWillMount method.

For instance, we can write:

class App extends React.Component {
  constructor() {
    this.state = { position: 0, timer: undefined };
  }

  componentDidMount() {
    const timer = setTimeout(() => this.setState({ position: 1 }), 3000)
    this.setState({ timer });
  }

  componentWillUnmount(){
    clearTimeout(this.state.timer);
  };

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

We called setTimeout with a callback with the timeout time span in componentDidMount to get the timer when the component loads.

It returns a timer object that we can call clearTimeout with to clear the resources for the timer when the component unmounts./

We have the timer state to set the timer returned from setTimeout to the state.

Then we in componentWillUnmount , we call clearTimeout to clear the timer.

setInterval in a React Component

Like with setTimeout , we can call setInterval within a React component.

It’s pretty much the same as setTimeout except that we can setInterval and clerInterval .

For instance, we write:

class App extends React.Component {
  constructor() {
    this.state = { position: 0, timer: undefined };
  }

  componentDidMount() {
    const timer = setInterval(() => this.setState(state => ({ position: state.position + 1 })), 3000)
    this.setState({ timer });
  }

  componentWillUnmount(){
    clearInterval(this.state.timer);
  };

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

We called setInterval in componentDidMount to create a timer to run code periodically.

In the setInterval callback, we update the position state every 3 seconds.

Then in componentWillUnmount , we call clearInterval to clear the timer.

With function components, we can do the same thing.

For instance, we can write:

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

const App = () => {
  const [position, setPosition] = useState(0);
  const timer = () => setPosition(position => position + 1);

  useEffect(() => {
    const timer = setInterval(timer, 1000);
    return () => clearInterval(timer);
  }, []);

  return <div>{position}</div>;
};

We have the useState hook to update the position state with setPosiitin .

Then we have the useEffect hook to create a timer when the component loads.

Then function we return in the useEffect callback removes the timer with clearInterval .

The empty array in the 2nd argument ensures that the useEffect callback only runs when App first loads.

Conclusion

We can create a component to redirect to an external URL.

Also, we can use setTimeout and setInterval in our components.

To set prop types, we can use the prop-types package.

Categories
React Tips

React Tips — Detect KeyPress, Unique IDs, and Remove Items

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.

Generate Unique IDs for Form Labels in React

We can generate unique IDs with the Lodash or Underscpre’s uniqueId method.

For instance, we can write:

class App extends React.Component {
  `constructor(props) {
    super(props);
    this.id = _.uniqueId("form-");
  }

  render() {
    const id = this.id;
    return (
      <div>
        <input id={id} type="text" />
        <label htmlFor={id}>label</label>
      </div>
    );
  }
}`

We called uniqueId and assigned the returned value as the value of the id prop.

The argument for the method is the prefix for the ID.

With function components, we can write:

import React, { useState } from 'react';
import uniqueId from 'lodash/uniqueId';

const App = (props) => {
  const [id] = useState(uniqueId('form-'));
  return (
    <div>
      <input id={id} type="text" />
      <label htmlFor={id}>label</label>
    </div>
  );
}

We imported the uniqueId function and then put it in useState .

This way, we can get the ID as variable and use it in our form child elements.

Detect Esc Key Press in React

We can detect the Esc key by adding a keydown event handler into our component.

For instance, we can write:

class Page extends React.Component {
  constructor(props){
    super(props);
    this.onKeyPress = this.onKeyPress.bind(this);
  }

  onKeyPress(event){
    if(event.keyCode === 27) {
      //...
    }
  }

  componentDidMount(){
    document.addEventListener("keydown", this.onKeyPress, false);
  }

  componentWillUnmount(){
    document.removeEventListener("keydown", this.onKeyPress, false);
  }

  render(){
    return (
      <input />
    )
  }
}

We add an event listener for the keydown event by calling documebnt.addEventListener in the componentDidMount method.

This will ensure that the event listener is added when the component mounts.

Likewise, we can removeEventListener to remove the event listener to ensure that it’s unloaded when the component unmounts.

this.onKeypress is the event handler.

In the method, we check the keyCode property to get the code for the key pressed.

27 is the code for the Esc key.

With function components, we can use the useEffect hook to add and remove the listener.

For instance, we can write:

import React, { useEffect } from 'react';

const App = () => {

  useEffect(() => {
    const handleEsc = (event) => {
       if (event.keyCode === 27) {
        console.log('Close')
      }
    };
    window.addEventListener('keydown', handleEsc);

    return () => {
      window.removeEventListener('keydown', handleEsc);
    };
  }, []);

  return(<p><input /></p>);
}

We have the useEffect hook with a callback to add the keydown listener.

We call addEventListener when the component mounts with addEventListener .

The empty array in the 2nd argument ensure that it loads only when the component mounts,

We call removeEventListener when the component unmounts to remove the listener when it unmounts.

The event listener code is the same as the previous example.

Delete Item from State Array in React

We can delete an item from a state array by calling splice on the original array and then calling setState to set that as the new value of the state array.

For instance, we can write:

removePeople(e) {
  const people = [...this.state.people];
  const index = array.indexOf(e.target.value);
  if (index !== -1) {
    people.splice(index, 1);
    this.setState({ people });
  }
},

First, we make a copy of the array so that we can modify it without changing the original array.

Then we get the index that we want to remove.

Then we call splice to remove the item from the array copy.

And then we call setState to set that as the new value.

We can also use the filter method to return a new array that includes the items that we want to keep.

For example, we can write:

class ItemsList extends Component {
  constructor() {
    this.state = {
      itemsList: [
        {
          id: 1,
          name: 'All Items',
        }, {
          id: 2,
          name: 'In Stock Items',
        }
      ],
    }
     this.removeItem = this.removeItem.bind(this)
  }

  removeItem(deleteItemId) {
     this.setState({
       itemsList: this.state.itemsList.filter(item => item.id != deleteItemId)
        })
   }

  render(){
    return <div />
  }
}

We called filter to return a new array that includes only the items with id value other than deleteItemId .

Then we call setState to set that as the new value of itemsList state.

Conclusion

We can generate unique ID with Underscore or Lodash methods.

There are a few ways to remove an item from a state array.

And there are multiple ways to detect Esc key press.

Categories
React Tips

React Tips — Mock React-Redux, Internationalization, and Connect Redux with React

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 Unit Test React-Redux Connected Components

We can test a React-Redux connected component by mocking the connect function and Provider component with our own code.

For instance, we can write:

jest.mock('react-redux', () => {
  return {
    connect: (mapStateToProps, mapDispatchToProps) => (Component) => ({
      mapStateToProps,
      mapDispatchToProps,
      Component
    }),
    Provider: ({ children }) => children
  }
})

We create a mock version of React Redyx by creating a mock module with the connect function.

It takes a mapStateToProps and mapDispatchToProps methods like the real thing.

And it returns a function that takes a React component and returns an object with all the parameters in it.

To mock the Provider we just return the children from the prop.

This can be used inline within a file.

To put the mock in a separate file, we can write:

module.exports = {
  connect: (mapStateToProps, mapDispatchToProps) => (Component) => ({
    mapStateToProps,
    mapDispatchToProps,
    Component,
  }),
  Provider: ({children}) => children
};

in __mocks__/react-redux.js .

The __mocks__ folder should be in the root folder.

Unless we call jest.unmock(‘react-redux’)) the mock will be used.

PropTypes in Stateless Functional Component

We can set prop types in stateless function components.

For instance, we can write:

import React from 'react';
import PropTypes from 'prop-types';

function List(props) {
  const todos = props.todos.map((todo, index) => (<p key={index}>{todo}</p>));
  return (<div>{todos}</div>);
}

List.propTypes = {
  todos: PropTypes.array.isRequired,
};

We assign the propTypes property with an object with the prop types.

And then we use the PropTypes object to specify the type.

How to Maintain State After a Page Refresh in React

To maintain state after a page refresh in React, we can store the state we want to keep in local storage.

For instance, we can write:

constructor() {
  const selectedOption = localStorage.getItem('selectedOption');
  this.state = {
    selectedOption
  };
}

setSelectedOption(option) {
  localStorage.setItem('selectedOption', option);
  this.setState({ selectedOption: option });
}

We have the constructor that gets the saved state from local storage with getItem .

Then in another method, we set the option in the local storage and the state.

Use Redux’s Store with React

To access a Redux store with a React component, we can use the connect function.

For instance, we can write:

import { connect } from 'react-redux'
import { setVisibilityFilter } from '../actions'
import Link from '../components/Link'

const mapStateToProps = (state, ownProps) => {
  return {
    active: ownProps.name === state.name
  }
}

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    onClick: () => {
      dispatch(setName(ownProps.name))
    }
  }
}

const NameLink = connect(
  mapStateToProps,
  mapDispatchToProps
)(Link)

export default NameLink

With our mapStateToProps function, we return the active Redux state as a prop for the Link component.

Also, we have the mapDispatchToProps function to let us create a function that calls dispatch dispatch an action to our Redux store.

Then we can pass them all to the connect function, which returns a higher-order component.

Then we can pass in our Link component to return a new component to add the state and dispatch functions as props.

How to use FormattedMessage in input placeholder with React-Intl

To pass in a placeholder that’s translated with the react-intl, we can call the formatNwessage method with an object to interpolate the placeholders.

For instance, we can write:

import React from 'react';
import { injectIntl, intlShape } from 'react-intl';

const Input = ({ intl }) => {
  const placeholder = intl.formatMessage({ id: 'messageId' });
  return(
     <input placeholder={placeholder} />
  );
}

Input.propTypes = {
  intl: intlShape.isRequired
}

export default injectIntl(Input);

We use the injectIntl higher-order component to inject the intl prop to our component.

It has the formatMessage method that we can interpolate our placeholders with.

It returns a string so that we can use it in in our placeholder prop.

With function components, we can use the useIntl hook to do the same thing.

For instance, we can write:

import React from 'react';
import { useIntl } from 'react-intl';

const Input = () => {
  const intl = useIntl();
  const placeholder = intl.formatMessage({ id: 'messageId' });
  return(
     <input placeholder={placeholder} />
  );
};

export default Input;

We use the useIntl hook to get the intl object.

Then we can call formatMessage on it to interpolate our string.

Conclusion

We can use the react-intl for internationalization.

Also, the react-redux module can be mocked in our tests.

Props types can be set in function components.

We can save our state to local storage to make it persist during refresh.