Categories
React Tips

React Tips — Function Props, Query Strings, and Default Props

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.

Listen to State Changes in React

We can listen to state changes to React in several ways.

In class components, we can use the componentDidUpdate hook to listen for state and prop changes.

We can write:

componentDidUpdate(object prevProps, object prevState)

There’s also the componentWillUpdate method which is deprecated.

With function components, we can use the useEffect hook to watch for changes.

For instance, we can write:

const [name, setName] = useState('foo');
useEffect(getSearchResults, [name])

We pass in an array with the variables that we want to watch in the 2nd argument of the useEffect hook.

The first argument is a callback that’s called when name changes.

Pass Props in Link with React Router

We can pass in a query string to the Link .

For instance, we can write:

<Link to={{ pathname: `/foo/bar`, query: { backUrl } }} />

We set the query property with an object.

The object’s keys and values are transformed into a query string that’s attached after the pathname .

We can also take URL parameters with placeholders:

<Route name="/foo/:value" handler={CreateIdeaView} />

Then we can get it by using:

this.props.match.params.value

To get the query string, we can write:

this.props.location.search

to get the value.

Then we can use the URLSearchParams constructor to parse it and the values in it:

new URLSearchParams(this.props.location.search).get("foo")

If we have a query string ?foo=bar , then that will return 'bar' .

Call Parent Method with React

We can call a parent component’s method if we pass a function from the parent to the child as a prop.

For instance, we can write:

import React, {Component} from 'react';

class Child extends Component {
  render () {
    return (
      <div>
        <button
          onClick={() => this.props.someFunc('foo')}
        >
          click me
        </button>
      </div>
    )
  }
}

class Parent extends Component {
  someFunc(value) {
    console.log(value)
  }

  render() {
    return (
      <div>
        <Child
          someFunc={this.someFunc.bind(this)}
        />
      </div>
    )
  }

}

We pass the function from parent to child with the someFunc prop in the Parent component.

Then in the Child component, we call the function with this.props.someFunc .

Using function components, we can write:

import React from "react";

function Child(props){
  return(
    <>
      <button onClick={props.parentFunc}>
        click me
      </button>
    </>
  );
}

function Parent(){
  const parentFunc = () => {
    console.log("parent func called");
  }

  return (
    <>
      <Child
        parentFunc={parentFunc}
      />
    </>
  );
}

We have the Parent component which has the parentFunc that we pass to the Child component as a prop.

Then we called it by calling props.parentFunc when we click on the button in the Child component.

Import and Export Components Using React, ES6 and Webpack

To export components in a React project, we should export it as a default export.

For instance, we can write:

SomeNavBar.js

import React from 'react';
import Navbar from 'react-bootstrap/lib/Navbar';

export default class SomeNavBar extends React.Component {
  render(){
    return (
      <Navbar className="navbar-dark" fluid>
        {//...}
      </Navbar>
    );
  }
}

Then we import it with whatever name we want.

For instance, we can write:

import SomeNavBar from './SomeNavBar';

to import the navbar component.

We don’t put curly braces in default exports.

Set component Default Props on React Component

To set default props on a React component, we can use the prop-types package.

We’ve to install it by running:

npm i prop-types

Then we can write:

import PropTypes from 'prop-types';

class Address extends React.Component {
  render() {
    const { street, city } = this.props;
    <p>{street}, {city}</p>
  }
}

Address.defaultProps = {
  street: 'street',
  city: 'city',
};

Address.propTypes = {
  street: PropTypes.string.isRequired,
  city: PropTypes.string.isRequired
}

We set the defaultProps property to set the default prop values.

The object has the prop names as the keys and the default values as the values.

propTypes has the prop types for each prop.

We set them both to string and make them required with isRequired .

Conclusion

We can set default props and validate their format with the prop-types package.

We listen to state changes with class component lifecycle methods or the useEffect hook for function components.

Also, we can get and set query strings and URL parameters with React Router.

We can pass functions as props from parent to child.

Categories
React Tips

React Tips — Context, Hover, and Input Fields

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.

Get the Value of an Input Field Using React

To get the value of an input field with React, first, we set the inputted value to a state.

Then we get the latest value from the state.

For instance, we can write:

class InputForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      val: ''
    };
  }

  render() {
    return (
      //...
      <input value={this.state.val} onChange={evt => this.updateInputValue(evt)}/>
      //...
    );
  },

  updateInputValue(evt) {
    this.setState({
      val: evt.target.value
    });
  }
});

We created the updateInputValue method which calls setState to set the value of the input field as the value of the val state.

Then we pass that into the onChange prop.

The value prop has the this.state.val which we set.

With function components, we use the useState hook to set the value and retrieve it.

For instance, we can write:

import { useState } from 'react';

function InputForm() {
  const [val, setVal] = useState('');

  return (
    <div>
      <input value={val} onInput={e => setVal(e.target.value)}/>
    </div>
  );
}

We called the useState function with the initial value of the input.

Then we passed a function to the onInput prop to run it to set the value to the val state when whenever something is entered.

Then we get the latest inputted value with the val variable.

Pass Form Element State to Sibling or Parent Elements

To most versatile way to pass data between element is to us the context APU.

For instance, we can write:

import React, { useState, useContext } from "react";
import ReactDOM from "react-dom";

const Context = React.createContext(null);

const initialAppState = {};

function App() {
  const [appState, updateAppState] = useState(initialAppState);

return (
    <div>
      <Context.Provider value={{ appState, updateAppState }}>
        <Comment />
      </Context.Provider>
    </div>
  );
}

function Comment() {
  const { appState, updateAppState } = useContext(Context);

  function handleCommentChange(e) {
    updateAppState({ ...appState, comment: e.target.value });
  }

  return (
    <div className="book">
      <input
        type="text"
        value={appState.comment}
        onChange={handleCommentChange}
      />
      <br />
      <div>
        <pre>{JSON.stringify(appState, null, 2)}</pre>
      </div>
    </div>
  );
}

We created the context with the React.createContext method to create the context.

Then in App, we add the Context.Provider so that all the child elements can have access to the context.

Then we created the Comment component which calls the useContext hook to use our Context context. In the component, we have an input to change the appState as we enter something. This will be reflected in all components that use the context.

We can see what we entered in the stringified JSON that’s below the input.

How to Implement a:hover with Inline CSS Styles in React

We can listen to the mouseenter and mouseleave events to create an effect for hover.

For instance, we can write:

class Foo extends React.Component {
  constructor() {
    this.state = { hover: false };
  }

  toggleHover(){
    this.setState({ hover: !this.state.hover })
  },

  render() {
    let linkStyle;
    if (this.state.hover) {
      linkStyle = { backgroundColor: 'red' }
    } else {
      linkStyle = { backgroundColor: 'green' }
    }
    return(
      <div>
        <a style={linkStyle} onMouseEnter={this.toggleHover} onMouseLeave={this.toggleHover}>Link</a>
      </div>
    )
  }
}

We created our component by adding a a element that listens to the mouseenter and mouseleave events by passing methods to the onMpuseEnter and onMouseLeave props.

The toggleHover method toggles the hover state between true and false .

Then in the render method, we set the backgroundColor property depending on the truth value of the hover state.

Also, we can use the style-it library which lets us embed CSS with pseudoclasses into our React components.

We install it by running:

npm install style-it --save

Then we can write:

import React from 'react';
import Style from 'style-it';

class Foo  extends React.Component {
  render() {
    return Style.it(`
      p:hover {
        color: red;
      }
    `,
      <p>hover me</p>
    );
  }
}

Then we use the Style.it tag from the style-it library to let us set the hover state of our element.

We can also use the Style component to do the same thing.

For instance, we can write:

import React from 'react';
import Style from 'style-it';

class Foo extends React.Component {
  render() {
    return (
      <Style>
        {`
          p:hover {
            color: red;
          }
        `}
        <p>hover me</p>
      </Style>
    );
  }
}

We use the Style component and embed our CSS with the hover pseudoclass in the string.

Then we’ll see a color change when we hover over the p element.

Conclusion

We can use a library or plain JavaScript to create a hover effect.

There are various ways to get input field values and pass data around multiple components.

Categories
React Tips

React Tips — Query Strings, Wrappers, and Clicks Outside

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.

Fix ‘Adjacent JSX elements must be wrapped in an enclosing tag’ Error

All components must have an outer element surrounding them.

For instance, we can write:

return (
  <div>
    <Child1 />
    <Child2 />
  </div>
)

We have a div surrounding all the child elements.

Also, we can use a fragment to surround our components if we don’t want to render a wrapper element.

For instance, we can write:

return (
  <>
    <Child1 />
    <Child2 />
  </>
)

or:

return (
  <React.Fragment>
    <Child1 />
    <Child2 />
  </React.Fragment>
)

Correct Way to Modify State Arrays in React

To modify a state array correctly in React, we should call setState ‘s state change function with a callback that returns the new array.

This way, we know the new value is derived from the most current value.

For instance, we can write:

this.setState(prevState => ({
  array: [...prevState.array, newThing]
}))

We add newThing to the end of the array.

If we use a function component, we can write:

`const [arr, setArr] = useState([]);
`//...
setArr(prevArr => [...prevArr, newThing]);

Detect Click Outside React Component

We can detect clicks outside a React component by listening to the documen ‘s click event.

This way, we can handle clicks of any element.

For instance, we can write:

import React, { Component } from 'react';


export default class App extends Component {
  constructor(props) {
    super(props);

    this.setWrapperRef = this.setWrapperRef.bind(this);
    this.handleClickOutside = this.handleClickOutside.bind(this);
  }

  componentDidMount() {
    document.addEventListener('mousedown', this.handleClickOutside);
  }

  componentWillUnmount() {
    document.removeEventListener('mousedown', this.handleClickOutside);
  }

  setWrapperRef(node) {
    this.wrapperRef = node;
  }

  handleClickOutside(event) {
    if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
      alert('clicked outside');
    }
  }

  render() {
    return <div ref={this.setWrapperRef}>hello</div>;
  }
}

We call the docuyment.addEventListener method to listen to the click event in the componentDidMount hook.

And we remove the listener with the component unmounts with removeListener in the componentWillUnmount hook.

Then we set the ref of the div so that we can check which element is clicked handleclickOutside and if it’s inside the component with contains .

Likewise, we can do the same with function components with hooks.

For instance, we can write:

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


function useClickOutside(ref) {
  useEffect(() => {
    function handleClickOutside(event) {
      if (ref.current && !ref.current.contains(event.target)) {
        console.log("clicked outside");
      }
    }

    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [ref]);
}

`export default function App() {
  const wrapperRef = useRef(null);` useClickOutside`(wrapperRef);

  return <div ref={wrapperRef}>hello</div>;
}`

We created the useClickOutside hook to add the event listener when the hooked loads.

Then in the function, we return in the useEffect callback, we remove the click listener.

We watch the ref for changes, so we have [ref] as the 2nd argument of useEffect .

Then we call useRef to create the ref, assign it to the div, and call useClickOutside with it.

How to Get Parameter Value from a Query String

If we’re using React Router, we can get the parameter value from the query string with the URLSearchParams constructor and the location.search prop.

For instance, we can write:

new URLSearchParams(this.props.location.search).get("foo")

this.prop.location.search has the query string.

Then we parse it into an object with URLSearchParams constructor.

And we call get with the key of the query parameter we want to get.

Also, we can use:

this.props.match.params.foo

to get the query parameter with key foo .

With the hooks version of the React Router, we can write:

import { useLocation } from 'react-router';
import queryString from 'query-string';

const App = React.memo((props) => {
  const location = useLocation();
  console.log(queryString.parse(location.search));

  return <p>search</p>;
}

We use the useLocation hook from React Router to get the location object from the hook.

Then we can use the queryString package to parse the query string.

We can also replace the query-string package with the URLSearchParams constructor:

import { useLocation } from 'react-router';

const App = React.memo((props) => {
  const location = useLocation();
  console.log(new URLSearchParams(location.search));

  return <p>search</p>;
}

Conclusion

We should wrap our components with a root element or fragment.

The right way to modify arrays is to pass in a function to setState or state change function.

We can watch for clicks outside a component by adding event listeners.

Also, we can get the query string from the component with React Router.

Categories
React Tips

React Tips — Copy to Clipboard, Comparing Old and New Values with Hooks

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 Copy Text to Clipboard

We can copy text to the clipboard by using the navigator.ckipboard.writeText method.

For instance, we can write:

<button
  onClick={() =>  navigator.clipboard.writeText('copy this to clipboard')}
>
  copy to clipboard
</button>

We copy the text in the string in the argument to the clipboard.

Also, we can use the react-copy-to-clipboard package to make our lives easier.

For instance, we can write:

import React from 'react';
import ReactDOM from 'react-dom';
import {CopyToClipboard} from 'react-copy-to-clipboard';

class App extends React.Component {
  state = {
    value: '',
    copied: false,
  };

  onChange({target: {value}}) {
    this.setState({value, copied: false});
  },

  render() {
    return (
      <div>
        <input value={this.state.value} onChange={this.onChange} />

        <CopyToClipboard text={this.state.value}
          onCopy={() => this.setState({copied: true})}>
          <span>Copy to clipboard with span</span>
        </CopyToClipboard>

      </div>
    );
  }
}

The package comes with the CopyToClipboard component.

It takes the text prop with the text that we want to copy to the clipboard.

The onCopy prop is run when the text is copied.

Inside the component, we have the content that we can click to do the copying.

Once the element is clicked, the content in the text prop will be copied to the clipboard.

We can also use the execCommand method to copy the content of a DOM element that’s selected to the clipboard.

For instance, we can write:

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

export default function CopyExample() {

const [copySuccess, setCopySuccess] = useState('');
  const textAreaRef = useRef(null);

  function copyToClipboard(e) {
    textAreaRef.current.select();
    document.execCommand('copy');
  };

  return (
    <div>
      {
       document.queryCommandSupported('copy') &&
        <div>
          <button onClick={copyToClipboard}>Copy</button>
          {copySuccess}
        </div>
      }
      <form>
        <textarea
          ref={textAreaRef}
          value='text to copy'
        />
      </form>
    </div>
  );
}

We have a functional component with the copyToClipboard to select the text from our text area.

The selection is done by:

textAreaRef.current.select();

textAreaRef is the ref that we assigned to the text area.

Then we call the execCommand with the 'copy' argument to copy the text that’s selected to the clipboard.

In the JSX we return, we check if the copy command is supported with:

document.queryCommandSupported('copy')

and display a button to let us copy the data if it is.

We also have the text area that has the stuff to copy.

Identifying Different Inputs with One onChange Handler

We can use one event handler for multiple inputs.

To do that, we can create an event handler function that takes an argument to identify the input that we’ve changed.

For instance, we can write:

class App extends React.Component {
  constructor() {
    super();
    this.state = { input1: 0, input2: 0 };
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(input, value) {
    this.setState({
      [input]: value
    })
  }

  render() {
    return (
      <div>
        <input type="text" onChange={e => this.handleChange('input1', e.target.value)} />
        <input type="text" onChange={e => this.handleChange('input2', e.target.value)} />
      </div>
    )
  }
}

We pass in a callback that calls the handleChange method with the key of the state that we want to change when the text is entered.

This way, we can change the input that we want.

setState in handleChange has a computed property name instead of a fixed property.

Compare Old Values and New Values with the useEffect Hook

We can use the useRef hook to get the previous value.

And we can get the latest values from the component itself.

For instance, we can write:

const usePrevious = (value) => {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

const App = (props) => {
  const { amount, balance } = props
  const prevAmount = usePrevious({ amount, balance });
  useEffect(() => {
    if (prevAmount.amount !== amount) {
      //...
    }

    if (prevAmount.balance !== balance) {
      //...
    }
  }, [amount, balance])

  //...
}

We created the usePrevious hook to get the previous values with useRef .

We set the old values to that we passed into the hook function by setting the values to the ref.current property.

The previous values are then returned from the hook.

In the App component, we get the latest values from the props.

And we get the old values from the usePrevious hook.

Then we can compare them in the useEffect callback.

The array that we passed in has the values that we want to watch for changes for.

Conclusion

We can set the previous values with the useRef hook.

There are various ways to copy text from a component to the clipboard.

We can identify different inputs in a component by creating our own event handler to identify them.

Categories
React Tips

React Tips — Wrappers, Render Props, and setState Errors

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.

Fix the ‘Warning: setState(…): Cannot update during an existing state transition’ Error

To fix this error, we shouldn’t call methods in the render method.

For instance, in the constructor, we put our state change methods:

this.handleButtonTrue = this.handleButtonChange.bind(this, true);
this.handleButtonFalse = this.handleButtonChange.bind(this, false);

Then in our render method. we write:

<Button onClick={this.handleButtonTrue}>true</Button>
<Button onClick={this.handleButtonFalse}>false/Button>

When to use React setState Callback

We should use the React setState ‘s callback when we need to run some code that always runs after a state change.

For instance, we can write:

changeTitle(event) {
  this.setState({ title: event.target.value }, () => {
    this.validateTitle();
  });

},
validateTitle() {
  if (this.state.title.length === 0) {
    this.setState({ error: 'no blank title' });
  }
},

We call setState to change the title state.

Then we run validateTitle to validate the latest value of the title state.

React Prop Validation for Date Objects

We can validate that date objects are passed in as props with the instanceof method.

We can write:

PropTypes.instanceOf(Date)

to do the validation.

Best Way to Access Redux Store Outside a React Component

We can access a Redux store outside a React component by exporting the value returned from createStore .

Then we can use that value anywhere we like.

For instance, in store.js , we write:

const store = createStore(myReducer);
export store;

Then in app.js , we write:

import { store } from './store'
store.dispatch(
  //...
)

If we want to use multiple stores, we can write a function that creates a store if it doesn’t exist and return a promise with the store.

Then we can use that to get the store.

Wrapping One Component into Another

To let us wrap one component in another, we create a wrapper component with that takes the children prop

For instance, we can write:

const Wrapper = ({children}) => (
  <div>
    <div>header</div>
    <div>{children}</div>
    <div>footer</div>
  </div>
);

const App = ({name}) => <div>Hello {name}</div>;

const App = ({name}) => (
  <Wrapper>
    <App name={name}/>
  </Wrapper>
);

We create a Wrapper component which takes the children prop.

Then we create a App component which we put inside our Wrapper component.

We can also use render props to pass components into another.

This means we pass the whole render function into another component.

For instance, we can write:

class Wrapper extends React.Component {
  state = {
    count: 0
  };

  increment = () => {
    const { count } = this.state;
    return this.setState({ count: count + 1 });
  };

  render() {
    const { count } = this.state;

  return (
      <div>
        {this.props.render({
          increment: this.increment,
          count: count
        })}
      </div>
    );
  }
}

class App extends React.Component {
  render() {
    return (
      <Wrapper
        render={({ increment, count }) => (
          <div>
            <div>
              <p>{count}</p>
              <button onClick={() => increment()}>Increment</button>
            </div>
          </div>
        )}
      />
    );
  }
}

We created a Wrapper which takes a render prop that takes a function that renders components.

We passed in a value for the render prop in App .

Then that’s called within Wrapper with the object that as the increment and count properties.

The increment method is passed in from App and as well as the count state.

Validate the PropTypes of a Nested Object in React

We can validate prop types of a nested object bu using the shape method.

For instance, we can write:

import PropTypes from 'prop-types';

propTypes: {
  data: PropTypes.shape({
    firstName: PropTypes.string.isRequired,
    lastName: PropTypes.string
  })
}

We call the PropTypes.shape method with an object that describes the structure of the data prop.

We have 2 strings and isRequired indicates that it’s required.

How to Add Comments in React?

We can add comments by putting them between curly braces.

For instance, we can write:

<div>
  {/* button click */}
  <Button whenClicked={this.handleClick}>click me </Button>
  <List />
</div>

Out comment is within the curly braces.

They’re the same as regular JavaScript comments.

Conclusion

We can add comments if we put them between the curly braces.

We shouldn’t call setState in our render method.

A Redux store can be accessed outside a React component.

We can nest child components by creating a wrapper component that takes the children prop.

Or we can accept a render prop in our component that renders components.