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.

Categories
React Tips

React Tips — GraphQL Queries, URL Parameters and React Router

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.

Make GraphQL Queries with React Apollo

We can make GraphQL queries with React Apollo by using the client.query method.

This is available once we update the component by calling withApollo function.

For instance, we can write:

class Foo extends React.Component {
  runQuery() {
    this.props.client.query({
      query: gql`...`,
      variables: {
        //...
      },
    });
  }

  render() {
    //...
  }
}

export default withApollo(Foo);

The client.query method will be available in the props once we call withApollo with our component to return a component.

The method takes an object that has the query and variables properties.

The query property takes a query object returned by the gql form tag.

variables has an object with variables that we interpolate in the query string.

We can also wrap our app with the ApolloConsumer component.

For example, we can write:

const App = () => (
  <ApolloConsumer>
    {client => {
      client.query({
        query: gql`...`,
        variables: {
          //...
        }
      })
    }}
  </ApolloConsumer>
)

We can make our query in here.

For function components, there’s the useApolloClient hook.

For instance, we can write:

const App = () => {
  const client = useApolloClient();
  //...
  const makeQuery = () => {
    client => {
      client.query({
        query: gql`...`,
        variables: {
          //...
        }
      })
    }
  }
  //...
}

The hook returns the client that we can use to make our query.

There’s also the useLazyQuery hook that we can use to make queries.

For instance, we can write:

const App = () => {
  const [runQuery, { called, loading, data }] = useLazyQuery(gql`...`)
  const handleClick = () => runQuery({
    variables: {
      //...
    }
  })
  //...
}

runQuery lets us make our query.

React Router Pass URL Parameters to Component

We can pass URL parameters if we create a route that allows us to pass parameters to it.

For instance, we can write:

const App = () => {
  return (
    <Router>
      <div>
        <ul>
          <li>
            <Link to="/foo">foo</Link>
          </li>
          <li>
            <Link to="/bar">bar</Link>
          </li>
          <li>
            <Link to="/baz">baz</Link>
          </li>
        </ul>

        <Switch>
          <Route path="/:id" children={<Child />} />
        </Switch>
      </div>
    </Router>
  );
}

function Child() {
  const { id } = useParams();

  return (
    <div>
      <h3>ID: {id}</h3>
    </div>
  );
}

We have a Child component that has the useParams hook.

It lets us get the URL parameters that we want and it’s passed in from navigation.

It returns the URL parameter as a key-value pair.

The keys are what we defined and the value is what we have passed when we navigate.

In App , we have the Link components with the paths.

And also we have the Switch components that have the route that takes the id URL parameter.

The Route has the route that we pass in. children has the component that’s displayed.

Preventing Form Submission in a React Component

There are several ways to prevent form submission in a React component.

If we have a button inside the form, we can make set the button’s type to be button.

For instance, we can write:

<button type="button" onClick={this.onTestClick}>click me</Button>

If we have a form submit handler function passed into the onSubmit prop;

<form onSubmit={this.onSubmit}>

then in th onSubmit method, we call preventDefault to stop the default submit behavior.

For example, we can write:

onSubmit (event) {
  event.preventDefault();
  //...
}

TypeScript Type for the Match Object

We can use the RouteComponentProps interface, which is a generic interface that provides some base members.

We can pass in our own interface to match more members if we choose.

For example, we can write:

import { BrowserRouter as Router, Route, RouteComponentProps } from 'react-router-dom';

interface MatchParams {
  name: string;
}

interface MatchProps extends RouteComponentProps<MatchParams> {}

const App = () => {
  return (
    <Switch>
      <Route
         path="/products/:name"
         render={({ match }: MatchProps) => (
            <Product name={match.params.name}
         /> )}
      />
    </Switch>
  );
}

We use the MatchProps interface that we created as the type for the props parameter in the render prop.

Then we can reference match.params as we wish.

Conclusion

We can make GraphQL queries in a React component with the React Apollo client.

React Router lets us pass in URL parameters easily.

It works with JavaScript and TypeScript.

We can prevent form submission with event.preventDefault() in the submit handler.

Categories
React Tips

React Tips — Formik Blur, Router Navigation, Context Value

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.

Ternary Operator in JSX to Include HTML

We can add the ternary operator to include HTML by writing the following

render () {
  return (
    <div>
      {(this.state.message === 'success')
          ? <div>successful</div>
          : <div>not successful</div>
      }
    </div>
  );
}

Change Context Value While Using React Hook of useContext

We can pass in the state change function to the context to let us call them anywhere.

This way, we can change the value in whatever component that receives the context.

For example, we can write:

const { createContext, useContext, useState } = React;

const ThemeContext = createContext({});

function Content() {
  const { style, color, toggleStyle, changeColor } = useContext(
    ThemeContext
  );

  return (
    <div>
      <p>
        {color} {style}
      </p>
      <button onClick={toggleStyle}>Change style</button>
      <button onClick={() => changeColor('green')}>Change color</button>
    </div>
  );
}

function App() {
  const [style, setStyle] = useState("light");
  const [color, setColor] = useState(true);

  function toggleStyle() {
    setStyle(style => (style === "light" ? "dark" : "light"));
  }

  function changeColor(color) {
    setColor(color);
  }

  return (
    <ThemeContext.Provider
      value={{ style, visible, toggleStyle, changeColor }}
    >
      <Content />
    </ThemeContext.Provider>
  );
}

We created the ThemeContext , which we use in the App component to get the provider and wrap that around the Content component.

Then we pass our state change functions with the state variables into the context by passing them into the object in the value prop.

Then in the Content component, we can call the toggleStyle and toggleStyle and changeColor functions to change the states in App .

We get those functions in Content with the useContext hook.

Simulate a Change Event with Enzyme

We can simulate a change event with Enzyme by creating a spy for the handle change method.

For instance, we can write:

it("responds to name change", done => {
  const handleChangeSpy = sinon.spy(Form.prototype, "handleChange");
  const event = { target: { name: "name", value: "spam" }};
  const wrap = mount(
    <Form />
  );
  wrap.ref('name').simulate('change', event);
  expect(handleChangeSpy.calledOnce).to.equal(true);
})

We create a spy for our change event listener.

Then we set our event object.

And then we mount our Form component that we want to test.

And then we trigger the change event on it with the simulate method.

Then we checked that the spy is called once.

How to Use Custom onChange and onBlur with React Formik

We can create our own blur handler by writing:

<Field
    component={MyInput}
    name="email"
    type="email"
    onBlur={e => {
        handleBlur(e)
        let someValue = e.currentTarget.value
        //...
    }}
/>

We call the built-in handleBlur function.

Then we do something else in the lines after.

How to Use React Router with Electron

We can use React Router in an Electron app with the HashRouter ,

For instance, we can write:

<HashRouter
  basename={basename}
  getUserConfirmation={() => {}}
  hashType='slash'
>
  <App />
</HashRouter>

basename is a string with the base URL for all locations.

getUserConfirmation is a function that lets us use to confirm navigation.

hashType is a string that has the encoding to use for window.location.hash .

The possible values are 'slash' , which is #/ .

'noslash' is # .

And 'hashbang' us #!/ .

Cannot Read Property ‘push’ of undefined With React Router

We can use the withRouter higher-order component to make the history object available.

For instance, we can write:

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

  handleClick(value) {
    this.props.history.push('/dashboard');
  }

  render() {
    return (
      <div>
        <Route
          exact
          path="/"
          render={() => (
            <div>
              <h1>Welcome</h1>
            </div>
          )}
       />
       <Route
         path="/dashboard"
         render={() => (
           <div>
             <h1>Dashboard</h1>
           </div>
         )}
      />
      <button onClick={this.handleClick} >go to dashboard</button>
    );
  }
}

export default withRouter(App);

We have several routes and a handleClick method to let us go to the dashboard route.

We have the this.props.history.push method because we called withRouter higher-order component with App .

Conclusion

We can navigate to routes programmatically with withRouter .

We can pass anything to a context so that we can use them anywhere else.

Formik’s blur handler can be replaced with our own function.