Categories
React Tips

React Tips — Watching Props, Downloads, and Media Queries

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.

Run Async Code on Update of State with React Hooks

We can watch for the change of the state with the useEffect hook.

The 2nd argument takes an array that can hold the values that we want to watch.

When they change, the callback in the first argument will run.

For instance, we can write:

function App() {
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    if (loading) {
      doSomething();
    }
  }, [loading]);

  return (
    <>
      <div>{loading}</div>
      <button onClick={() => setLoading(true)}>click Me</button>
    </>
  );
}

We have the useEffect hook that watches the loading state.

If it changes, then the callback will load.

It’ll change when we click the click me button.

It sets the loading state to true .

How to Download Fetch Response in a React Component as a File

We can download the response retrieved by the Fetch API as a file by converting the result to a blog.

Then we can download it by clicking on an invisible link.

For instance, we can write:

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

  componentDidMount() {
    fetch('./file.pdf')
      .then(res => {
        return res.blob();
      }).then(blob => {
        const href = window.URL.createObjectURL(blob);
        const a = this.linkRef.current;
        a.download = 'file.pdf';
        a.href = href;
        a.click();
        a.href = '';
      })
      .catch(err => console.error(err));
  }

  render() {
    return (
      <a ref={this.linkRef}/>
    );
  }
}

We have a link assigned to our ref.

Then with the fetch function, we make a GET request for file.pdf .

Then we convert that to a blob with res.blob()

Once we did that, we pass the blob into the createObjectURL method.

Then we get the link and set the download property to set the file name.

href is set to the object URL we created.

And then we call click to start the download.

And we clear the link by setting href to an empty string.

Updating State with Props on React Child Component

In a child component, we can update the states with props by returning a state in getDerivedStateFromProps.

For instance, we can write:

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    }
  }

  static getDerivedStateFromProps(props) {
    return {
      count: props.count * 2
    }
  }

  // ...
}

We get the count from the props and then we doubled it and return that as the value of the count state.

It’s a static method, unlike most other class component methods.

It’s called every time a component is rendered, regardless of the update.

It’s asynchronous so it’s consistent with other methods, which are also async.

We shouldn’t commit side effects in the method.

If we need to commit side effects, we should do them elsewhere.

Inline CSS Styles in React and Media Queries

We can add CSS styles in the form of inline JavaScrip with the react-responsive package.

It supports adding media queries.

We can install it by running:

npm install react-responsive --save

Then we can write:

import React from 'react'
import { useMediaQuery } from 'react-responsive'

const App  = () => {
  const isDesktopOrLaptop = useMediaQuery({
    query: '(min-device-width: 1224px)'
  })
  const isBigScreen = useMediaQuery({ query: '(min-device-width: 2000px)' })
  const isTablet = useMediaQuery({ query: '(max-width: 1500px)' })
  const isMobile = useMediaQuery({
    query: '(max-device-width: 1000px)'
  })
  const isPortrait = useMediaQuery({ query: '(orientation: portrait)' })

  return (
    <div>
      <p>{isBigScreen && 'big screen'}</p>
      <p>{isTablet && 'tablet screen'}</p>
      <p>{isMobile && 'mobile screen'}</p>
      <p>{isPortrait && 'portrait screen'}</p>
    </div>
  )
}

It comes with th useMediaQuery hook that lets us add media queries for the screen with a given width or orientation.

We have one for the big screen, media query, mobile, and portrait screens.

They all return boolean according to screen size and orientation.

Then we can use them in our JSX code to create responsive layouts.

Conclusion

There are packages for adding media queries with JavaScript.

We can run async code with useEffect .

We can also watch for prop changes and does updates accordingly.

And we can download files in a React component.

Categories
React Tips

React Tips — Styles, Clone Element, and Nav Bar

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 ‘style prop expects a mapping from style properties to values, not a string’ Error

We’ve to pass in an object to the style prop.

For instance, we can write:

<span style={{ float: 'left', paddingRight: '5px' }} >foo</span>

We pass in an object with camel-cased properties instead of kebab-case.

Also, we can import styles from a file with the import keyword.

For instance, we can write:

styles.css

.color{
  color: "red";
  background: "#0f0";
}

Then we write:

import './styles.css';

const Button = (props) => {
  return (
    <div>
      <span className="color">{props.age}</span>
    </div>
  );
};

const infos = {
  age: 20
};

ReactDOM.render(<Button {...infos} />, mountNode);

We import the styles.css and then the styles will be applied.

React useReducer Async Data Fetch

useReducer can be used instead of useState if we’re changing a state that’s set after lots of computation.

If we have complex state logic with multiple sub-values in the state, or when the next state depends on the previous one, then we can use this hook.

For instance, we can write:

const initialState = {};

function reducer(state, action) {
  switch (action.type) {
    case 'profileReady':
      return action.payload;
    default:
      throw new Error();
  }
}

function App(props) {
  const [profile, setProfile] = React.useReducer(reducer, initialState);

  useEffect(() => {
    reloadProfile()
      .then((profileData) => {
        setProfile({
          type: "profileReady",
          payload: profileData
        });
    });
  }, []);

  return (
    <div>{profile.name}</div>
  );
}

We have a reducer that sets the state.

And we have an initial state that we can pass in.

We can pass them both into the useReducer hook.

It returns the state and the state setter function in this order.

Then we can use that with the useEffect to get data and set it.

The empty array in the 2nd argument make sure that the callback is only run only when the component is loaded.

How to Refresh a Page Using React Router Link

We can reload a page without using anything from React Router.

For instance, we can write:

window.location.reload();

to reload the page.

Create a Nav Bar with React Router

To create a navbar with React Router, we use the components that are bundled with React Router to create the routes.

For instance, we can write:

import React from "react";
import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";

export default function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/dashboard">Dashboard</Link>
            </li>
          </ul>
        </nav>

        <Switch>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/dashboard">
            <Dashboard />
          </Route>
          <Route path="/">
            <Home />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

function Home() {
  return <h2>Home</h2>;
}

function About() {
  return <h2>About</h2>;
}

function Dashboard() {
  return <h2>Dashboard</h2>;
}

We create a few components that we use as routes.

Then we use the in the Switch component to create our routes.

We have the Route component inside it and we nest the component we want to display inside.

The navbar is created with the nav component.

And inside it, we have the Link components to create the links to display the route components.

to is the path of the component that we want to display.

And it should match one of the path values in the Switch .

To do navigation, we can call history.push to navigate.

For instance, we can write:

<a onClick={() => history.push('dashboard') }>Dashboard</a>

to navigate programmatically.

Assign the Correct Typing to React.cloneElement When Giving Properties to Children

We can set the type of the child component to the React.ReactElement type.

For instance, we can write:

return React.cloneElement(child as React.ReactElement<any>, {
  name: this.props.name,
  age: this.props.age
});

if child is an element.

We can also use the isValidElement type guard.

For example, we can write:

if (React.isValidElement(child)) {
  return React.cloneElement(child, {
    name: this.props.name,
    age: this.props.age
  });
}

This will let the TypeScript compiler determine the type automatically without adding any data type assertions.

Conclusion

cloneElement can be used with child elements in React by setting the right type or using a type guard.

Styling can be done with various items.

We can create a navbar easily with React Router.

Categories
React Tips

React Tips — Restricted Routes, Booleans, Wrapping, and Select Values

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.

Restrict Access to Routes in React Router

We can restrict access to routes by checking for credentials.

Then we can return the component if the credentials are valid.

Otherwise, we redirect to the path that we want to redirect to.

For instance, we can write:

export default function AuthenticatedRoute({ component: Component, appProps, ...rest }) {
  return (
    <Route
      {...rest}
      render={props =>
        appProps.isAuthenticated
          ? <Component {...props} {...appProps} />
          : <Redirect
              to={`/login?redirect=${props.location.pathname}${props.location.search}`}
            />}
    />
  );
}

export default function App() {
  const [authenticated, setAuthenticated] = useState(false);

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

  async function onLoad() {
    try {
      await getSession();
      setAuthenticated(true);
    } catch (e) {
      console.log(e);
    }
  }

  return (
    <div>
      <Switch>
        <AuthenticatedRoute
          path="/profile"
          component={Profile}
          appProps={{ authenticated }}
        />
        <Route component={Login} path="/login" />
      </Switch>
    </div>
  );
}

We created the AuthenticatedRoute that takes the component we want to restrict.

We check for the credentials in the component.

Then if it’s valid, we return the component to render it.

Otherwise, we return the Redirect component to redirect to the login route.

Toggle Boolean State of React Component

We can toggle the boolean state of a React component by calling setState with the opposite value of the state that we have now.

For instance, we can write:

class A extends React.Component {
  constructor() {
    super()
    this.handleCheckBox = this.handleCheckBox.bind(this)
    this.state = {
      checked: false
    }
  }

  handleCheckBox(e) {
    this.setState({
      checked: e.target.checked
    })
  }

  render(){
    return <input type="checkbox" onChange={this.handleCheckBox} checked={this.state.checked} />
  }
}

We have a checkbox that we passed the this.handleCheckBox method to update the checked state.

Then we update the state by calling setState in there.

Then we set the checked prop to the this.state.checked state.

With function components, we can write:

import React from "react";

function App(props) {
  const [toggled, setToggled] = React.useState(false);

  return  (
    <button
      onClick={(event) => {
       setToggled(!toggled);
     }}
    >
      {toggled.toString()}
    </button>;
}

We set the toggled state when we click the button to the opposite of the existing value of the toggled state.

Then we see what we have by setting the string as version of toggled as the content of the button.

Default Export of a Component

To export a component as a default export, we can write:

const Header = () => {
  return <p>hello</p>
};
export default Header;

or:

export default () => (
  <p>hello</p>
)

We define our const variable separately and then we export it.

Or we export the component directly.

Conditionally Wrap a React component

To conditionally wrap a React component, we can create a higher-order component to do the conditional wrapping.

For instance, we can write:

const WithLink = ({ link, className, children }) => (link ?
  <a href={link} className={className}>
    {children}
  </a>
  : children
);

const Link = ({ link, className, count }) => {
  return (
    <WithLink link={link} className={className}>
      <i className={styles.Icon}>
        {count}
      </i>
    </WithLink>
  );
}

We created a WithLink higher-order component to get the link and then use that to check if we should put a wrapper around our component.

Then in our Link component, we get the link and className props and pass them into the WithLink component.

We pass the count prop into the icon class.

Get Values from a <select> Element with Multiple Option in React

We can create a component with the select element that can accept multiple selections.

Then we can add an onChange handler to get the options from the select element.

For instance, we can write:

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

  handleChange(e) {
    this.setState({ multiValue: [...evt.target.selectedOptions].map(o => o.value) });
  }

  render() {
    return (
      <select multiple value={this.state.multiValue} onChange={this.handleChange}>
        <option value='apple'>Apple</option>
        <option value='orange'>Orange</option>
        <option value='grape'>Grape</option>
      </select>
    );
  }
}

We get all the selected options with the evt.target.selectedOptions property.

Then we map each entry to their value by returning the value property.

Conclusion

We can get all the selected values of the multiple select elements with the evt.target.selectedOptions.

Also, we can create restricted routes with React Router.

And we can toggle a boolean state when we do something to a React component.

Categories
React Tips

React Tips — Input Event, Redux, Forward Ref and Bubbling

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.

Best Way to Trigger Change Event in React

We can trigger events programmatically by getting the native input value setter.

Then we can trigger the input event with it instead of React’s version.

For instance, we can write:

const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;
nativeInputValueSetter.call(input, 'something');

const ev = new Event('input', { bubbles: true });
input.dispatchEvent(ev);

We get the native input value setter with:

const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, "value").set;

Then we create a native input event by writing:

nativeInputValueSetter.call(input, 'something');

The first argument is the input element.

The 2nd is the value of the input.

Then we created the event with:

const ev = new Event('input', { bubbles: true });

And then we dispatch the input event on the input element with:

input.dispatchEvent(ev);

Prevent Event Bubbling in Nested Components on Click

We can prevent event bubbling in nested components on click by using the stopProphation method.

For instance, we can write:

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

  handleClick(e) {
    e.stopPropagation();
    this.props.onClick();
  }

  render() {
    return (
      <li onClick={this.handleClick}>
        {this.props.children}
      </li>
    )
  }
}

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

  handleClick(e) {
    // ...
  }
  render() {
    return (
      <ul onClick={this.handleClick}>
        <ListItem onClick={this.handleClick}>Item</ListItem>
      </ul>
    )
  }
}

Since we have a click listen for the ul element and multiple click listeners for the li elements, we’ve to call stopPropagation on the li elements’ click handlers so that the click event won’t bubble up to the ul element and beyond.

We did that with:

e.stopPropagation();

in the handleClick method of ListItem .

Use React.forwardRef in a Class-Based Component

We can use React.forwardRef in a class-based component by passing in a callback that returns the class-based component inside.

For instance, we can write:

class DivComponent extends Component {
  render() {
    return (
      <div ref={this.props.innerRef}>
        foo
      </div>
    )
  }
}

const Comp = React.forwardRef((props, ref) => <DivComponent
  innerRef={ref} {...props}
/>);

We pass in a callback with the props and ref parameters and we return the DivComponent with the props and ref passed in as props of it.

Then we can access the ref by referencing the this.props.innerRef so that we can assign it as the ref of the div.

Simple Dispatch from this.props Using connect with Redux

We can map our dispatch functions to props by using the mapDispatchToProps method.

For instance,e we can write:

const mapDispatchToProps = (dispatch) => {
  return {
    onClick: () => dispatch(decrement())
  };
}

to map the dispatch call for the decrement action to the onClick prop.

We can also put the dispatch function into the object to access it directly:

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

We can also use bindActionCreators to turn:

function mapDispatchToProps(dispatch) {
  return {
    onPlusClick: () => dispatch(increment()),
    onMinusClick: () => dispatch(decrement())
  };
}

to:

import { bindActionCreators } from 'redux';

const mapDispatchToProps = (dispatch) => {
  return bindActionCreators({
    onPlusClick: increment,
    onMinusClick: decrement
  }, dispatch);
}

We mapped the increment and decrement actions to the onPlusClick and onMinusClick props.

And we can shorten that to:

const mapDispatchToProps = (dispatch) => {
  return bindActionCreators({ increment, decrement }, dispatch);
}

Then we just get the increment and decrement from the props and call them to dispatch the actions.

We can shorten it even more by turning:

const mapDispatchToProps = (dispatch) => {
  return bindActionCreators({ increment, decrement }, dispatch);
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App);

Into:

export default connect(
  mapStateToProps,
  { increment, decrement }
)(App);

This will inject increment and decrement as props without mapDispatchToProps .

Update Single Value Inside Specific Array Item in Redux

We can update a single value inside a specific array item in Redux writing our reducer in a way that divides the array, modifies the entry we want to change, and join them back together.

For instance, we can write:

case 'MODIFY_ARRAY':
   return {
       ...state,
       contents: [
          ...state.contents.slice(0, index),
          { title: "title", text: "text" },
         ...state.contents.slice(index + 1)
       ]
    }

We called slice to divide the array into chunks. Then we have our next object between the chunks.

Then we use the speed operator to join them back together into one array.

Conclusion

There are many shorthands for mapDispatchToProps .

We can change an array entry by returning a new array in a reducer.

We can call stopPropagation to stop event bubbling.

Also, we can trigger an input event programmatically with the native input value setter.

Categories
React Tips

React Tips — Redux States, Dynamic Elements, and Pretty Print JSON

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.

Access Store State in React Redux

We can access store state in React Redux with the mapStateProps method.

For instance, we can write:

import React from "react";
import { connect } from "react-redux";

const App = (props) => {
  return (
    <div>
      <h1>{props.name}</h1>
    </div>
  );
}

const mapStateToProps = state => {
  return {
    name: state.name
  };
};
export default connect(mapStateToProps)(App);

We call connect with mapStateToProps to add the Redux store states as props of the App component.

Then we can just get it with props.name as we did in App .

Render Repeating React Elements

We can render repeating React elements with the map method.

For instance, we can write:

{this.props.titles.map(title =>
  <div key={title}>{title}</div>
)}

We have the titles prop and call map to return a div from each title entry.

We cal also use the Array.from method to make an array from something that’s not an array.

For instance, we can write:

<div>
  { Array.from({ length: 3 }, (value, index) => <div key={value.id}>}{value.name}</div>) }
</div>

We called Array.from create an empty array with length of 3, then we map the empty slots to an element.

There’s also the Array.fill method to render the elements from empty array slots:

<div>
 { Array(3).fill(<div />) }
</div>

Toggle Class when Clicked in a React Component

We can set a state to let us toggle a class when we click something in a React component.

For instance, we can write:

class App extends Component {
  constructor(props) {
    super(props);
    this.addActiveClass = this.addActiveClass.bind(this);
    this.state = {
      active: false,
    };
  }

  toggleClass() {
    const currentState = this.state.active;
    this.setState({ active: !currentState });
  };

  render() {
    return (
      <div
        className={this.state.active ? 'active': null}
        onClick={this.toggleClass}
      >
        <p>hello</p>
      </div>
    )
  }
}

We have the toggleClass method which is called when we click on the div.

In the method, we set the active state to the opposite of the current value.

Then we get the class name depending of the value of this.state.active .

Dynamically Add Child Components in React

To dynamically add child components to React, we can change the state, and then we can render what we want based on the state.

For instance, we can write:

class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      data: [
        { id: 1, name: "foo" }
      ]
    }
    this.addChild = this.addChild.bind(this);
  }

  addChild() {
    const newData = { id: 2, name: "bar" };
    this.setState(state => [...state.data, newData])
  }

  render() {
    return (
      <div>
         <button onClick={this.addChild}>Add name</button>
         {this.state.data.map((item) => (
            <div key={item.id}>{item.name></div>
         )}
      </div>
    );
  }
}

We have the addChild method which calls setState to set the new value of data by passing in a callback to append the new entry to the data state.

Then in the render method, we map the data state to an entry in by calling array instance’s map method.

We return a component or element we want to display.

Pretty Printing JSON with React

We can pretty print JSON with React with the pre element.

For instance, we can write:

class PrettyPrintJson extends React.Component {
  render() {
    const { data }= this.props;
    return (<div><pre>{JSON.stringify(data, null, 2) }</pre></div>);
  }
}

We called JSON.stringify with 2 as the 3rd argument to indent the data that we display as the data.

With a function component, we can write:

const PrettyPrintJson = ({data}) => (
  <div>
    <pre>
      {JSON.stringify(data, null, 2)}
    </pre>
  </div>
);

We just return the JSX expression for pretty print directly.

Also, we can cache the JSON data with React.memo .

For example, we can write:

const PrettyPrintJson = React.memo(
  {data}) => (
    <div>
      <pre>
        {JSON.stringify(data, null, 2)}
      </pre>
    </div>
  )
);

Conclusion

We can render repeated elements by using array methods to map data to JSX expressions.

Also, we can pretty-print JSON by using JSON.stringify to pretty print our JSON with indentation.

We can toggle classes and render elements dynamically by changing states and then rendering whatever we want with the render method.

Finally, we can use mapStateToProps to map Redux states to props.