Categories
React Tips

React Tips — super, Call Child Methods, Debounce, and Inlint 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.

Difference Between “super()” and “super(props)” in React when Using ES6 Classes?

The only difference between the 2 is when we need to access props in the constructor.

If we need to get them in the constructor, then we’ve to get the props from the parameters and pass it into super .

For instance, we write:

class MyComponent extends React.Component {
  constructor(props) {
    super(props)
    console.log(this.props);
  }

  render(){
    //...
  }
}

If we don’t, then we can skip it:

class MyComponent extends React.Component {
  constructor(props) {
    super()
  }

  render(){
    //...
  }
}

Inline Style Best Practices

We can put inline styles by passing in an objecty with the styles or className prop.

For instance, we can write:

<li
 className={classnames({ 'list-item': true, 'is-complete': item.complete })} />

We used the classnames package to dynamically set the class names of the li element.

Also, we can write:

<li style={Object.assign({}, fooStyles, barStyles)}>

We just set the styles by passing in an object with all the style properties.

The keys have the attributes and the values are the values.

Does render Get Called Any Time “setState” is Called?

setState is called every time render is called.

This is why we can’t use setState in the render method.

Otherwise, we’ll get an infinite render loop.

If we don’t want it to be called on every setState call, we should have the shouldComponentUpdate hook.

We can compare the state and props and return a boolean expression with the condition to notify React when the component should render.

showComponentUpdate gas the following signature:

shouldComponentUpdate(nextProps, nextState)

Perform Debounce in React

We can denounce with React by using the awesome-debounce-promise package,

For instance, we can write:

const searchAPI = text => fetch(`/search?text=${encodeURIComponent(text)}`);

const searchAPIDebounced = AwesomeDebouncePromise(searchAPI, 500);

class SearchInputAndResults extends React.Component {
  state = {
    text: '',
    results: null,
  };

  search = async text => {
    this.setState({ text, results: null });
    const result = await searchAPIDebounced(text);
    this.setState({ result });
  };
  //...
}

We use the AwesomeDebouncePromise function to delay the searchAPI function by 500 ms.

Then in the sesrch method, we use the promise returned by the package and use setState to set the data.

We can also use it with function components.

For instance, we can write:

const searchAPI = text => fetch(`/search?text=${encodeURIComponent(text)}`);

const searchAPIDebounced = AwesomeDebouncePromise(searchAPI, 500);`

const App = () => {
  const [results, setResults] = useState([]);
  const [text, setText] = useState(['');`

  search = async text => {
    const result = await searchAPIDebounced(text);
    `setResults`(result);
  };

 return (
    <div>
      <input value={setText} onChange={e => setText(e.target.value)} />
      <div>
        {results && (
          <div>
            <ul>
              {results.map(r => (
                <li key={r.name}>{r.name}</li>
              ))}
            </ul>
          </div>
        )}
      </div>
    </div>
  );
};

We use the same function and the useState hook to set the state when it’s done.

This is all done in the search function.

Call Child Method from Parent

We can call a child method from a parent by forwarding the ref to the child.

Then we can get the child’s method from the ref.

For instance, we can write:

const Child = forwardRef((props, ref) => {
  useImperativeHandle(ref, () => ({
    hello() {
      console.log("hello Child");
    }
  }));

  return <h1>Hi</h1>;
});

const Parent = () => {
  const childRef = useRef();

  return (
    <div>
      <Child ref={childRef} />
      <button onClick={() => childRef.current.hello()}>Click</button>
    </div>
  );
};

We call forwardRef on the child with a callback that returns our component.

The useImperrativeHandle hook gets the ref and returns an object w8itht eh methods we want to call.

Then in the parent, we pass the ref to the ref prop.

Then we call current.hello to call the method in the child.

If we use class components, then it’s simpler.

For instance, we can write:

const { Component } = React;

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

  onClick = () => {
    this.child.current.hello();
  };

  render() {
    return (
      <div>
        <Child ref={this.child} />
        <button onClick={this.onClick}>Click</button>
      </div>
    );
  }
}

class Child extends Component {
  hello() {
    conole.log('hello child');
  }

  render() {
    return <h1>Hello</h1>;
  }
}

We create a Child with the hello method which we call from the Parent .

Then we just assign a ref to it and call it with current.hello .

Conclusion

We can call child component function from the parent.

If we need to access props in the constructor, then we need to pass them into super .

We can denounce event handlers with 3rd party libraries.

Categories
React Tips

React Tips — Default Props and TypeScript, Copy Text to Clipboard

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.

Display Loading Screen While DOM is Rendering in Class Components

We can create a loading display in a React class component by putting our code in a few hooks.

For instance, we can write:

class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      loading: true,
    }
  }

  componentDidMount() {
    this.timerHandle = setTimeout(() => this.setState({ loading: false }), 2000);
  }

  componentWillUnmount(){
    if (this.timerHandle) {
      clearTimeout(this.timerHandle);
    }
  }

  render(){
    return !loading && <div>hello world</div>;
  }
}

We have an App component, which has a timer created by calling setTimeout in the componentDidMount hook. It sets the loading state to false after 2 seconds. It’s initially set to true in the constructor. In our render method, we check the loading state and render something if it’s false .

Default Property Value in React Component Using TypeScript

We can set the default prop value in a React component by setting the defaultProps property in the component class.

For instance, we can write:

interface ItemProps {
  foo: string;
  bar: string;
}

export class Item extends React.Component<ItemProps, {}> {
  public static defaultProps = {
    foo: "default"
  };

  public render(): JSX.Element {
    return (
      <span>{this.props.foo.toUpperCase()}</span>
    );
  }
}

We created the ItemProps interfaces with a few properties. Then we pass that into the generic type parameter of React.Component to specify the prop names and types that are allowed. Inside the class, we set the static defaultProps property to set the default value of a prop.

With function components, we can write:

interface ItemProps {
  foo?: string;
  bar: number;
}

const ItemComponent: FunctionComponent<PageProps> = (props) => {
  return (
    <span>{props.foo}, {props.bar}</span>
  );
};

ItemComponent.defaultProps = {
  foo: "default"
};

We create an interface and then we pass it into the type parameter of the FunctionComponent generic type. Then we set the props’ default values with the defaultProps property.

useState Set Method Not Reflecting Change Immediately

useState ‘s state setting methods won’t reflect the changes immediately. They’ll be reflected in the next render cycle. To watch for the latest value of the state, we can use the useEffect hook.

For instance, we ecan write:

useEffect(() => { console.log(movies) }, [movies])

to watch for the latest value of the movies state.

React Component Names Must Begin with Capital Letters

We should create React components with names that begin with capital letters. This way, we can distinguish them between regular HTML elements and React components.

Get Derived State from Props

We can get derived state from props with memoize-one package. It’ll help us cache the values that are computed from props.

To install it, we run:

npm i memoize-one

Then we can use it by writing:

import memoize from "memoize-one";

const computeDerivedState = (props) => {
  //..
  return derivedState;
}

class App extends React.Component {
  constructor(){
    this.getDerivedData = memoize(computeDerivedState);
  }

  render() {
    const derivedData = this.getDerivedData(this.props.someValue);
    //...
  }
}

We have a computeDerivedState function which takes the props and compute something from them. Then we can use it in our render function to compute the value or get the memorized one if needed.

How to Copy Text to Clipboard

We can copy text to the clipboard by using the document.execCommand method.

For instance, we can write:

import React from 'react';

class Copy extends React.Component {

  constructor(props) {
    super(props);
    this.state = { copySuccess: '' }
  }

  copyToClipboard(e){
    this.textArea.select();
    document.execCommand('copy');
  };

  render() {
    return (
      <div>
        {
         document.queryCommandSupported('copy') &&
          <div>
            <button onClick={this.copyToClipboard}>Copy</button>
            {this.state.copySuccess}
          </div>
        }
        <form>
          <textarea
            ref={(textarea) => this.textArea = textarea}
            value='foo bar'
          />
        </form>
      </div>
    );
  }

}

We have a text area with some text we can copy. It’s assigned a ref so we can access its content later when we copy the text. We check if the copy command is supported by the document.queryCommandSupported method. We display the copy button if it’s supported. The button will call the copyToClipboard method if it’s clicked. In the method, we call the select method on the text area to select the text to copy. Then we run document.execCommand to run the copy command.

Conclusion

We can copy text to the clip with the copy command. Also, we can display things differently when our content is loading. Default prop values can be set with TypeScript and React. Thanks for reading my article, I hope you found it helpful!

Categories
React Tips

React Tips — Check Why Component Rerenders, Paths, and Loading Screens

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.

Add Dynamic Class to Manual Class Names

We can add dynamic classes with template string.

For instance, we can write:

className={`foo bar ${this.state.something}`}

where this.state.something is a string.

Also, we can use the classNames package to make setting classes dynamically easier.

For instance, we can write:

render () {
  const btnClass = classNames({
    'btn': true,
    'btn-pressed': this.state.isPressed
  });
  return <button className={btnClass}>click me</button>;
}

We call the classNames function that comes with the package and then we can set the conditions for adding the classes as the value.

The class name is in the key.

Trace Why a React Component is Re-rendering

We can write our own code to trace why a React component is re-rendering.

In a class component, we can check what values are rendered within the componentDidUpdate lifecycle method.

As its name suggests, it runs when the component is updated.

For instance, we can write:

componentDidUpdate(prevProps, prevState) {
  for (const [key, val] of Object.entries(this.props)){
     prevProps[key] !== val && console.log(`prop '${key}' changed`)
  }

  if(this.state) {
    for (const [key, val] of Object.entries(this.props)){
       prevState[key] !== val && console.log(`state'${key}' changed`)
    }
  }
}

We loop through the key-value pairs of the props and state and see what has changed.

We only log if there’re previous props or state.

If we’re using function components, we can create our own hook to log what’s changed.

For instance, we can write:

function useUpdate(props) {
  const prev = useRef(props);
  useEffect(() => {
    const changedProps = Object.entries(props).reduce((ps, [k, v]) => {
      if (prev.current[k] !== v) {
        ps[k] = [prev.current[k], v];
      }
      return ps;
    }, {});

    if (Object.keys(changedProps).length > 0) {
      console.log(changedProps);
    }
    prev.current = props;
  });
}

function App(props) {
  useUpdate(props);
  return <div>{props.children}</div>;
}

We created the useUpdate gook that use the useRef hook to get the previously stored values of the props.

Then we listen for changes to everything with the useEffect hook.

We get the changed props by looping through the props and then comparing them with the previous props we got from the useRef hook.

The props parameter has the latest props and prev has the previous props.

Then in our React component, we called our useUpdate hook with the props.

Difference Between <Route exact path=“/” /> and <Route path=“/” />

The exact prop lets us distinguish several paths that have similar names.

For instance, we can write:

<Switch>
  <Route path="/users" exact component={Users} />
  <Route path="/users/create" exact component={CreateUser} />
</Switch>

to distinguish between the /users and /users/create routes.

If we don’t have exact , then /users/create will be matched with the /users route.

Loop and Render elements in React.js Without an Array of Objects to Map

If we want to render an object’s properties to a list, we can use the Object.entries and array’s map methods.

For instance, we can write:

render() {
  return (
     <div>
       {obj && Object.entries(obj).map(([key, value], index) => {
          return <span key={index}>{value}</span>;
       }.bind(this))}
     </div>
  );
}

In our render method, we used Object.entries to get the key-value pairs of the object as an array.

Then we called map to render each property value into a span.

Display Loading Screen While DOM is Rendering

We can display a loading screen by setting the loading state in a component.

For instance, we can write:

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

const App = () => {
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    setTimeout(() => setLoading(false), 1000)
  }, []);

  return !loading && <div>hello world</div>;
};

We have the loading state and setLoading function returned by the useState hook.

We set it to true initially to see our loading message.

Then we use the useEffect hook to set the loading state to false as the content is loaded.

Then we can render the content we want when the loading state is false .

Conclusion

We can use the exact prop in React Router to match the routes exactly.

We can set a loading state to make it display.

Dynamic classes can be set with string interpretation of the classnames package.

We can watch for props and state changes in our components to see why our component is re-rendering.

Categories
React Tips

React Tips — Radio Buttons, Render HTML, and Initialize States

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.

Insert HTML with React

We can insert HTML in our React code.

To do that, we use the dangerouslySetInnerHTNL prop.

For instance, we can write:

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

We pass in an object with the __html property to render raw HTML.

someHtml is a string with the HTML content.

Initialize State from Props in a React Component

We can initialize the state from props in a React component by setting this.state in the constructor.

For instance, we can write:

class App extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      x: props.initialX
    };
  }
  // ...
}

We get the props from the props parameter and set it as a property of this.state .

Call Change Event Listener After Pressing Enter Key

To call a onChange event handler after pressing the enter key, we can listen to the keydown event.

For instance, we can write:

class App extends React.Component {
  handleKeyDown = (e) => {
    if (e.key === 'Enter') {
      console.log('entre pressed');
    }
  }

  render() {
    return <input type="text" onKeyDown={this.handleKeyDown} />
  }
}

We check the key property of the event object by comparing it to a string.

In a function component, we can write:

const App = () => {
  const handleKeyDown = (event) => {
    if (event.key === 'Enter') {
      console.log('enter pressed')
    }
  }

  return <input type="text" onKeyDown={handleKeyDown} />
}

The handleKeyDown function is the same.

Specify a Port to Run a create-react-app Based Project

We can change the port that a create-react-app project listens to by setting the PORT environment variable.

For instance, we can add:

"start": "PORT=3006 react-scripts start"

into the scripts section of package.json .

in Linux or Mac OS.

In Windows, we can put:

"start": "set PORT=3006 && react-scripts start"

into the scripts section of package.json .

Use Radio Buttons in React

We can use a radio button with React by setting the value the onChange event listener on the radio button.

For instance, we can write:

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

  handleChange = e => {
    const { name, value } = e.target;

    this.setState({
      [name]: value
    });
  };

  render() {
    return (
      <div>
        orange
        <input
          id="orange"
          value="orange"
          name="fruit"
          type="radio"
          onChange={this.handleChange}
        />
        grape
        <input
          id="grape"
          value="grape"
          name="fruit"
          type="radio"
          onChange={this.handleChange}
        />
        apple
        <input
          id="apple"
          value="apple"
          name="fruit"
          type="radio"
          onChange={this.handleChange}
        />
      </div>
    );
  }
}

We created multiple radio buttons with the same name attribute.

This way, we can choose one of them out of all the buttons.

In the handleChange method, we call setState with the e.target.name as the key and e.target.value as the value.

This sets the state with the name of the radio buttons which is fruit and the value will be the value of the value attribute.

With function components, we write:

const useInput = (initialValue) => {
  const [value, setValue] = useState(initialValue);

  function handleChange(e){
    setValue(e.target.value);
  }

  return [value, handleChange];
}

function App() {
  const [fruit, setFruit] = useInput("");

  return (
    <form>
      <div>
        <input type="radio" id='apple' value='apple'
        checked={fruit === 'apple'} onChange={setFruit}/>
        <label>apple</label>
      </div>
      <div>
        <input type="radio" id='orange' value='orange'
        checked={fruit === 'orange'} onChange={setFruit}/>
        <label>orange</label>
       </div>
       <div>
        <input type="radio" id='grape' value='grape'
        checked={fruit === 'grape'} onChange={setFruit}/>
        <label>grape</label>
       </div>
     </form>
  )
}

We created the radio buttons the same way, but we created our own useInput hook to make the change handling logic reusable.

In the hook, we used the useState method to set the state.

Then we return both the value , which always have the latest value, and handleChange , which has our event handler function.

Then we used the returned values of the useInput hook in our App component.

We passed the setFruit handler function which is returned as the 2nd entry of the array to the onChange prop.

Then the value will be set when we click the buttons.

We also have the checked prop to render the buttons with the proper checked values.

Conclusion

We can set radio buttons values with the handler function we pass into the onChange prop.

We’ve to set their name attributes to be the same.

To render raw HTML, we pass an object into the dangerouslySetInnerHTML prop.

Also, we can initialize states with props.

The port to run our create-react-app project can change.

Categories
React Tips

React Tips — Share Data, Mock Functions, and Local Storage

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 the Context Value in Provider from the Consumer

We can update the context value from the provider if we pass in the function into the context.

For instance, we can write:

const MyContext = React.createContext({});

class Child extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: ""
    };
  }

  onChange(e){
    const name = e.target.value;
    this.setState({
      name
    });
    this.props.context.updateValue('name', name);
  }

  render() {
    return (
       <React.Fragment>
         <input onChange={this.onChange} />
       </React.Fragment>
    )
  }
}

const withContext = (Component) => {
  return (props) => {
    <MyContext.Consumer>
      {(context) => {
           return <Component {...props} context={context} />
      }}
    </MyContext.Consumer>
  }
}

Child = withContext(Child)

class Parent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: "bar",
    };
  }

  updateValue = (key, val) => {
    this.setState({[key]: val});
  }

  render() {
    return (
      <MyContext.Provider value={{ state: this.state, updateValue: this.updateValue }}>
        <Child />
      </MyContext.Provider>
    )
  }
}

We create the context and pass the value from the Parent to the components in the context.

The object has the state and the updateValue function.

We then get the updateValue method from the props.context property, which is what we have.

Then we set the name by calling the updateValue method to set the name state of the Parent .

We’ve to remember to add the MyContext.Consumer to whatever component is consuming the context.

To do that, we created the withContext higher-order component to wrap any component with the context consumer.

getInitialState for React Class

We put the initial state in the constructor of a class component.

For instance, we can write:

import { Component } from 'react';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      foo: true,
      bar: 'no'
    };
  }

  render() {
    return (
      <div className="theFoo">
        <span>{this.state.bar}</span>
      </div>
    );
  }
}

We set the foo and bar states’ initial values in the constructor.

Using Local Storage with React

We can use the native local storage methods in React.

For instance, we can write:

import React from 'react'

class App extends React.Component {
  constructor(props) {
    super(props);
    const storedClicks = 0;

    if (localStorage.getItem('clicks')) {
      storedClicks = +(localStorage.getItem('clicks'));
    }

    this.state = {
      clicks: storedClicks
    };
    this.click = this.click.bind(this);
  }

  onClick() {
    const newClicks = this.state.clicks + 1;
    this.setState({ clicks: newClicks });
    localStorage.setItem('clicks', newClicks);
  }

  render() {
    return (
      <div>
        <button onClick={this.onClick}>Click me</button>
        <p>{this.state.clicks} clicks</p>
      </div>
    );
  }
}

We get the clicks from local storage if it exists.

Then we parse it if it exists and set that as the initial value of the clicks state.

Then in the render method, we have a button to update the clicks state and the local storage clicks value with the onClick method.

It updates the clicks state.

Also, we update the local storage’s clicks value after that.

Test a React Component Function with Jest

We can mock functions that our component depend on so that we can do testing with it.

For instance, we can write:

import React, { Component } from 'react';

class Child extends Component {
   constructor (props) {
      super(props);
   };

  render() {
      const { onSubmit, label} = this.props;
      return(
        <form  onSubmit={onSubmit}>
          <Button type='submit'>{label}</Button>
        </form >
      );
   };
};

export default class App extends Component {
  constructor (props) {
    super(props);
    this.label = “foo”;
  };

  onSubmit = (option) => {
    console.log('submitted');
  };

  render () {
    return(
      <div className="container">
        <Child label={this.label} onSubmit={this.onSubmit} />
      </div>
    );
  };
};

We can then mock the onSubmit function when we test the child by writing:

import React from 'react';
import { shallow } from 'enzyme';
import Child from '../Child';

const onSubmitSpy = jest.fn();
const onSubmit = onSubmitSpy;

const wrapper = shallow(<Child onSubmit={onSubmitSpy} />);
let container, containerButton;

describe("Child", () => {
  beforeEach(() => {
    container = wrapper.find("div");
    containerButton = container.find(“Button”);
    onSumbitSpy.mockClear();
  });

  describe("<Button> behavior", () => {
     it("should call onSubmit", () => {
       expect(onSubmitSpy).not.toHaveBeenCalled();
       containerButton.simulate(‘click’);
       expect(onSubmitSpy).toHaveBeenCalled();
     });
  });
});

We mount the component with the onSubmit prop populated by the onSubmitSpy , which is a mock function.

We tested by simulating a click event on the button of the Child component.

Then we check if the mocked function is called with toHaveBeenCalled .

Conclusion

We can pass around data with the context API.

Also, we can mock functions in with Jest so we can pass them in as props to test what we need to test.

Local storage can be used as-is in a React component.