Categories
React Tips

React Tips — Pseudo-Elements, Conditional Display and Constructor

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.

Conditionally Displaying Items in a React Component

We can conditionally display items in a React component in various ways.

One way is to use a ternary expression.

For instance, we can write:

render() {
  return (
    this.props.showMe ? <button type="submit">show me</button> : null
  );
}

The first item is shown if showMe is true and null is rendered otherwise.

We can also use the && operator.

For instance, we can write;

`{`showMe `&&` <button type="submit">show me</button>`}`

Is showMe is true then the button is rendered since the expression will be evaluated.

CSS Pseudo-elements in React

We can add prefixed styled by adding them as properties of the style object.

For instance, we can write:

render() {
  return (
    <div>
      <span>Something</span>
      <div style={{ WebkitFilter: 'blur(10px) saturate(2)' }} />
      </div>
  );
},

We have the WebkitFilter property which is equivalent to CSS’s -webkite-filter property.

To make our lives raise,r we can use the style-it package to convert any CSS property to JavaScript style properties.

To install it, we run:

npm install style-it --save

Then we can use it by writing:

import React from "react";
import Style from "style-it";
class Intro extends React.Component {
  render() {
    return Style.it(
      `
        .tooltip {
          display:inline-block;
          position:relative;
          border-bottom:1px dotted #666;
          text-align:left;
        }
        .tooltip .right {
          min-width:200px;
          top:50%;
          left:100%;
          margin-left:20px;
          transform:translate(0, -50%);
          padding:10px 20px;
          color:#444444;
          background-color:#EEEEEE;
          font-weight:normal;
          font-size:13px;
          border-radius:8px;
          position:absolute;
          z-index:99999999;
          box-sizing:border-box;
          box-shadow:0 1px 8px rgba(0,0,0,0.5);
          display:none;
        }
        .tooltip:hover .right {
          display:block;
        }
        .tooltip .right i {
          position:absolute;
          top:50%;
          right:100%;
          margin-top:-12px;
          width:12px;
          height:24px;
          overflow:hidden;
        }
        .tooltip .right i::after {
          content:'';
          position:absolute;
          width:12px;
          height:12px;
          left:0;
          top:50%;
          transform:translate(50%,-50%) rotate(-45deg);
          background-color:#EEEEEE;
          box-shadow:0 1px 8px rgba(0,0,0,0.5);
        }
    `,
      <div id="tooltip" />
    );
  }
}

We use the Style component with the CSS embedded in the string.

Then anything that comes after the string will be styled with the given styles.

Also, we can use the styled-components library to do the same thing.

We can install it by running:

npm i styled-components

Then we can write:

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

const Tooltip = styled.div`
  .tooltip {
    display:inline-block;
    position:relative;
    border-bottom:1px dotted #666;
    text-align:left;
  }
  .tooltip .right {
    min-width:200px;
    top:50%;
    left:100%;
    margin-left:20px;
    transform:translate(0, -50%);
    padding:10px 20px;
    color:#444444;
    background-color:#EEEEEE;
    font-weight:normal;
    font-size:13px;
    border-radius:8px;
    position:absolute;
    z-index:99999999;
    box-sizing:border-box;
    box-shadow:0 1px 8px rgba(0,0,0,0.5);
    display:none;
  }
  .tooltip:hover .right {
    display:block;
  }
  .tooltip .right i {
    position:absolute;
    top:50%;
    right:100%;
    margin-top:-12px;
    width:12px;
    height:24px;
    overflow:hidden;
  }
  .tooltip .right i::after {
    content:'';
    position:absolute;
    width:12px;
    height:12px;
    left:0;
    top:50%;
    transform:translate(50%,-50%) rotate(-45deg);
    background-color:#EEEEEE;
    box-shadow:0 1px 8px rgba(0,0,0,0.5);
  }
}
`;

const App = () => {
  return (
    <Tooltip>...</Tooltip>
  )
}

We used the styled.div template tag, which is a function that takes CSS styles and returns a component with the styles.

Then we can use them in our component as we did in App .

Functions in Stateless Components

We can call functions that are outside of the component within the component.

For instance, we can write:

const App = props => (
  <Something onClick={props.update} />
);

We can get functions from props and call them.

We can also have functions inside the component.

For instance, we can write:

const App  = props => {
  const onClick = useCallback((a, b) => {
    //...
  }, [props.x]);

  return (
    <Something onClick={onClick} />
  );
}

We use the useCallback gook to ensure that functions are only redefined when one of the dependencies in the array changes.

Calling super() in a React Component Constructor

We call super inside the constructor if we have to use this.props .

For instance, we writ:

class App extends React.component{
  constructor(props){
    super(props);
    console.log(this.props);
  }
}

So that we get access to this.props in our component’s code.

Subclasses must call super before referencing this either simplicity or explicitly.

Conclusion

We can use libraries to incorporate pseudo-classes in our React component code.

Also, we’ve to call super before using this in class components.

Items can be conditionally displayed with boolean expressions.

Categories
React Tips

React Tips — styled-components, Batch Updates, Child Validation

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 Batch State Update Batching with Hooks

If the state changes and triggered asynchronously, then they won’t be batched.

On the other hand, if they’re triggered directly, then they’ll be batched.

For instance, if we call multiple state change functions within a promise, then they won’t be batched:

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

function Component() {
  const [foo, setFoo] = useState('a');
  const [bar, setBar] = useState('b');

  const handleClickPromise = () => {
    Promise.resolve().then(() => {
      setFoo('aa');
      setBar('bb');
    });
  }

  return (
    <>
      <button onClick={handleClickPromise}>
        click me
      </button>
      <p>{foo} {bar}</p>
   </>
  );
}

If the state change functions are called in a promise as we have in the then callback, then they won’t be batched.

On the other hand, if we have:

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

function Component() {
  const [foo, setFoo] = useState('a');
  const [bar, setBar] = useState('b');

  const handleClick = () => {
    setFoo('aa');
    setBar('bb');
  }

  return (
    <>
      <button onClick={handleClick}>
        click me
      </button>
      <p>{foo} {bar}</p>
   </>
  );
}

Then they’ll be batched.

If they’re batched, then the updates will show up immediately.

Conditional Rendering in styled-components

To render something conditionally with a component created with styled-components, we can pass in a function into the string with the props as the parameter.

For instance, we can write:

const Button = styled.button`
  width: 100%;
  outline: 0;
  border: 0;
  height: 100%;
  justify-content: center;
  align-items: center;
  line-height: 0.2;

  ${({ active }) => active && `
    background: green;
  `}
`;

We have a bunch of static styles.

In the end, we have a function that takes the active prop.

Then we return 'background: green' with active is true .

The styled.button template tag is a function that’ll convert the style string to a component with the styles.

And then can use it by writing:

<Button active={this.state.active}></Button>

We can also add conditional styles to an existing component by writing:

const StyledFoo = styled(Foo)`
  background: ${props => props.active ? 'blue' : 'green'}
`

We use the styled function which takes a component and returns a template tag.

Then we create a string with a function interpolated in it that takes the props and returns 'blue' or 'green' depending on if the active prop is true or not.

Only Allow Children of a Specific Type in a React Component

To allow children of a specific type in a React component, we can loop through each entry of children and then throw an error if we see something we don’t want.

To do that, we can create a custom validation function in the object that we set as the value of the propTypes property.

For instance, we can write:

class ItemGroup extends Component {
  render() {
    return (
      <div>{this.props.children}</div>
    )
  }
}

ItemGroup.propTypes = {
  children(props, propName, componentName) {
    const prop = props[propName]
    let error = null
    React.Children.forEach(prop, (child) => {
      if (child.type !== Item) {
        error = new Error(`${componentName} children should be Items`);
      }
    })
    return error;
  }
}

We created our own prop validation method to validate the children prop.

We get all the children with React.children and call forEach on it to loop through each item.

In the callback, we get the child element that we’re looping through and we can check the type of it with the type property.

If it doesn’t return something of type Item , we set the error and return it.

Prevent Multiple Button Presses with React

To prevent multiple button presses with React, we can use the disabled prop to disable the button after we clicked the button.

For instance, we can write:

class App extends React.Component {
  this.state = {
    disabled : false
  };

  handleClick = (event) => {
    if (this.state.disabled) {
      return;
    }
    this.setState({ disabled: true });
  }

  render() {
    return (
     <button onClick={this.handleClick} disabled={this.state.disabled}>
      {this.state.disabled ? 'Sending...' : 'Send'}
     <button>
    );
}

We have the handleClick method that checks the disabled state.

If it’s true , we do nothing.

Otherwise, we set thedisabled state to true and the button will be disabled because we passed that value to the disabled prop.

Conclusion

We can disable buttons on click with the disabled prop.

State updates are batched if they’re called synchronously in function components.

Styling can be done conditionally with styleled-components.

Categories
React Tips

React Tips — Query Params, Inputs, Multiple Routes, Hooks vs Lifecycle Methods

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.

Programmatically Update Query Params in React Router

We can update query parameters with React Router by calling history.push .

We can either call it with an object:

history.push({
  pathname: '/cars',
  search: '?color=green'
})

or:

history.push('/car?color=green')

Change Event for contentEditable

Instead of listening to the change event to listen for content changes in a contentEditable element, we listen to the input event.

For instance, we can write:

<div
  contentEditable
  onInput={e => console.log(e.currentTarget.textContent)}
>
  foo bar
</div>

We pass an event handler to the onInput prop.

Then we can get the value of the content with e.currentTarget.textContent .

ReactJS Lifecycle Method Inside a Function Component

We replace the lifecycle methods with hooks in a function component.

useEffect is equivalent to the lifecycle hooks.

And useState is equivalent to setState .

For instance, we can write:

const Grid = (props) => {
  const [data, setData] = useState();

  const getData = () => {
    const data = await fetchData();
    setData(data);
  }

  useEffect(() => {
    getData();
  }, []);

  return(
    <div>
      {data.map(d => <Row data={data} />)}
    </div>
  )
}

We have the useState hook which returns the array with the latest state value and function to set the state.

Then we have the useEffect hook, which lets us commit side effects.

The 2nd argument is the values to watch for.

If it’s empty, then the callback in useEffect only runs when the component is mounted.

We can have multiple useEffect hooks in one component, unlike the lifecycle methods for class components.

Then we render the items in the JSX expression we return.

The equivalent of componentWillUnmount is the function that we return in the useEffect callback.

For instance, we can write:

useEffect(() => {
  window.addEventListener('click', handler);
  return () => {
    window.removeEventListener('click', handler);
  }
}, [])

We call any code that clears up resources in the function we return in the useEffect callback.

The equivalent of componentDidUpdate is passing in values to the array in the 2nd argument of useEffect .

For instance, if we want to watch for the change in values of the foo state and bar prop, we can write:

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

We just pass them into the array and then we always get the latest value.

Can’t Type into React Input Text Field

If we want to be able to type into an input text field, then we’ve to make it a controlled input.

This means we set a state’s value with the latest entered value in an event handler.

And we pass that into the onChange prop.

And we set the value prop to the value of that state.

For instance, we write:

<input
  type="text"
  value={this.props.value}
  onChange={this.handleChange}
/>

to do that.

For a full example, we can write:

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

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({ value: event.target.value });
  }

  handleSubmit(event) {
    alert(this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

The handleChange method sets the latest value that’s entered, which is stored in event.target.value as the value of the value state.

Then we can get that in the handleSubmit method when we click on Submit.

Multiple Path Names for the Same Component in React Router

We can assign multiple paths to redirect to the same path by passing in an array with all the path names to the path prop.

For instance, we can write:

<Router>
  <Route path={["/home", "/user", "/profile"]} component={Home} />
</Router>

We just pass them into the Router component’s path prop and they’ll all match.

Each pat in the array is a regex string.

Conclusion

Multiple path names can be assigned to go to the same component.

We can use history.push to update query parameters.

There are equivalents to component lifecycle methods in class components in function components.

To let us type into an input, we’ve to set the state with the latest inputted value and the set that as the value.

Categories
React Tips

React Tips — Props, this Binding, and Side Effects

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.

Conditionally Pass Prop Inline to a Component

We can conditionally pass prop inline to a component by passing in an expression as the prop value.

For instance, we can write:

<Child {...(this.props.canEdit ? { editOptions : this.state.options } : undefined)} >

We check the canEdit prop to see if it’s truthy.

If it is, then we pass in the editOptions prop to the child.

Otherwise, we passed in undefined .

We use the spread operator to spread the returned objects into props.

Use One or Many useEffect Hooks in a React Component

We can use the useEffect hook as many times as we want.

For instance, we can write:

useEffect(() => {
  // run code
  return () => {
    // run clean up code
  }
}, []);

useEffect(() => {
  // run code when props.foo changes
  return () => {
     // run clean up code when props.foo changes
  }
}, [props.foo])

The first useEffect call is used for running code when the component loads.

The function we return is run when the component unmounts.

In the 2nd useEffect call, we run code when props.foo changes.

And the function that’s return runs clean up code when props.foo changes.

It’s useful for triggering any side effects like an API call or anything like that.

Pass Properties Object to Child Component

We can pass an object’s properties to a child component by using the object spread operator.

For instance, we can write:

return <Child {...props} />;

The all the properties in the props object will be passed into Child as props.

Avoid Binding ‘this’ to Every Method

We can avoid binding all our methods to this by using class fields.

This isn’t part of the JavaScript syntax, but it can be used with Babel or TypeScript.

For instance, we can wire:

class Foo extends React.Component {

  onClick = () => {
    console.log('clicked');
  };

  onMouseOver = () => {
    console.log('mouse over');
  };

  render() {
    return (
      <div
        onClick={this.onClick}
        onMouseOver={this.onMouseOver}
      />
    );
  }

}

It’s still in Stage 3, so it’s not final.

Push Method in React Hooks

We can’t use the push method to append an item to an array since it returns the item that’s appended and changes the array in place.

Instead, we’ve to return a new array with the item that we wan tot append.

For instance, we can write:

const [array, setArray] = useState(initialArray);

Then we write:

setArray(oldArray => [...oldArray, newItem]);

We get the old array and return a new array with the items appended.

The existing items are spread into the new array with the spread operator.

PropTypes Check Object with Dynamic Keys

We can use a function to check an object with dynamic keys when we validate props.

For instance, we can write:

someProp: (props, propName, componentName) => {
  if (!/match/.test(props[propName])) {
    return new Error('match prop doesn't exist');
  }
}

We check if the value of someProp if the value of someProp matches the regex pattern we specified.

If it doesn’t then we throw an error.

props has the props as an object.

propName has the name of the prop.

componentName has the component name.

React propTypes: objectOf vs shape

The objectOf method methods lets us check if a prop value is of a certain type.

For instance, we can write:

number: PropTypes.objectOf(PropTypes.number)

to check if the value of the number prop is an object.

On the other hand, shape lets us check for the structure of an object.

For instance, we can write:

styleObj: PropTypes.shape({
  color: PropTypes.string,
  fontSize: PropTypes.number
}),

Then the styleObj prop has to have the color property, which is a string.

And it should have a fontSize property which is a number.

Conclusion

There are various ways to check the shape of an object we pass in as props.

We can pass properties into an object optionally by specifying a ternary expression.

Also, we can use useEffect multiple times in our component.

Dynamic keys can also be checked with custom functions with the prop-types package.

Categories
React Tips

React Tips — Sharing Data

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.

Update React Context from Inside a Child Component

We can update the React context by first creating a context, and wrapping the child component in the context consumer.

Then we can use the function returned by the useContext hook in the child component to do the update.

For instance,e we can write:

const NameContext = React.createContext({
  name: "",
  setName: () => {}
});

const NameSwitcher = () => {
  const { name, setName } = useContext(NameContext);
  return (
    <button onClick={() => setName("mary")}>
      change name
    </button>
  );
};

const App = () => {
  const [name, setName] = useState("");

  return (
    <NameContext.Provider value={{ name, setName }}>
      <h2>Name: {name}</h2>
      <div>
        <NameSwitcher />
      </div>
    </NameContext.Provider>
  );
};

First, we create the NameContext with the React.createContext method.

Then, we have the App component, which has the name state and setName to update the name state.

We then have the NameContext.Provider wrapped around all the component that we want to have access to NameContext .

The nesting can be at any level.

Everything in the value prop will be returned by useContext when we use it.

Therefore, in NameSwitcher , we can use the setName function to set the name state, which is also returned by useContext .

In class components, we can do the same thing.

For instance, we can write:

const NameContext = React.createContext({
  name: "",
  setName: () => {}
});

class NameSwitcher extends Component {
  render() {
    return (
      <NameContext.Consumer>
        {({ name, setName }) => (
          <button onClick={() => setName("mary")}>
            change name
          </button>
        )}
      </NameContext.Consumer>
    );
  }
}

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      language: "en",
      setLanguage: this.setLanguage
    };
    this.setName = this.setName.bind(this);
  }

  setName(name) {
    this.setState({ name });
  };

  render() {
    return (
      <NameContext.Provider value={{
        name: this.state.name,
        setName: this.setName
      }}>
        <h2>Name: {name}</h2>
        <div>
          <NameSwitcher />
        </div>
      </NameContext.Provider>
    );
  }
}

We have the same context object, but the state change functions, and the states are at different places.

We pass them into the value prop in on the object.

Since we passed them into the value prop’s object, we can access them in NameSwitcher .

The only difference is that we need to add a NameContext.Consumer and a callback inside it to access the properties.

They’re in the parameter of the callback.

Difference Between useCallback and useMemo

We use useMemo to memoize a calculation result a function’s calls and renders.

useCallback is for memoizing a callback itself between renders.

The reference is cached.

useRef is to keep data between renders.

useState does the same.

Therefore, we can use useMemo to avoid heavy calculations.

useCallback fixes performance issues where inline handlers cause a PureComponent ‘s child to render again.

This happens because function expressions are different referentially each time they render.

Make Ajax Request in Redux

We can make Ajax requests with Redux if we use the Redux Thunk middleware.

To install it, we run:

npm install redux-thunk

To use it, we write:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';

const store = createStore(rootReducer, applyMiddleware(thunk));

We import the rootReducer and the thunk middleware.

And we call applyMiddleware to apply the thunk middleware.

Now we can create our own thunk by writing:

const fetchUsers = () => {
  return dispatch => {
     fetch(`https://randomuser.me/api/`)
       .then(res => res.json())
       .then(res => {
          dispatch(saveUserData(res))
       })
   }
}

store
  .dispatch(fetchUsers())
  .then(() => {
    //...
  })

We pass a function that has the dispatch parameter, which is the Redux dispatch function, into the store.dispatch method.

The dispatch parameter is called to put the data into the Redux store.

Then to map this function to our component’s props, we can write:

function mapDispatchToProps(dispatch) {
  return {
    fetchUsers: () => dispatch(fetchUsers()),
  };
}

Now we can call this.prop.fetchUsers to call dispatch our async action.

fetchUsers is an action creator function, but it’s async.

It can be so thanks to the Redux Thunk plugin.

Conclusion

We can use the context API to share data with class and function components.

If we want a more flexible way to share data, we can use Redux with Redux Thunk.

This lets us set data in an async manner.