Tech notes for reactjs


React: Using React-Router intro

React-router is a library that lets you do routing in React. Let's use it.

Firstly, everything in your app must be surrounded by a BrowerRouter.

And you make links to different pages using <NavLink>. Let's make four links:

<div>
  <NavLink to="/">Main Page</NavLink>
  <NavLink to="/hello">Say Hello</NavLink>
  <NavLink to="/about/pink">About</NavLink>
  <NavLink to="/about/lightblue">About Blue</NavLink>
</div>

Note the third and fourth have url parameters. We'll use these later.

Finally, we must switch between the pages, so we use <Switch>. Inside that we use <Route>. And we specify a path which relates to the to attribute we used in the <NavLink>s (we also say it's exactly that - no fuzzy matching). Hext we have a component attribute we specifies the React component to render:

<Switch>
  ...
  <Route exact path="/" component={Main} />
  ...
</Switch>

If we want to use url parameters, and we do in the /about/pink and /about/lightblue links, we specify those in the path attribute of the <Route>. And then they appear in props.match.params in the component:

<Switch>
   ...
   <Route exact path="/about/:colour" component={About} />
   ...
</Switch>

....

function About({ match: { params } }) {
  return (
    <div style={{ backgroundColor: params.colour}}>
      I am the about page
    </div>
  )
}

Finally, if we want to pass props to our components, we use render instead of component. In render we return a component and you can pass a prop to that:

<Switch>
   ...
   <Route exact path="/hello" render={() => 
     <Hello name="Jakub"></Hello>
   } />
   ...
</Switch>

Here's the full example:

import { Route, BrowserRouter, NavLink, Switch } from 'react-router-dom';
...

function Main() {
  return (
    <div>I am the main page</div>
  )
}

function About({ match: { params } }) {
  return (
    <div style={{ backgroundColor: params.colour}}>
      I am the about page
    </div>
  )
}

function Hello({ name }) {
  return (
    <div>
      Hello, {name}
    </div>
  )
}

function App() {
  return (
    <BrowserRouter>
      <div>
        <div>
          <NavLink to="/">Main Page</NavLink>
          <NavLink to="/hello">Say Hello</NavLink>
          <NavLink to="/about/pink">About</NavLink>
          <NavLink to="/about/lightblue">About Blue</NavLink>
        </div>
        <hr />
        <Switch>
          <Route exact path="/" component={Main} />
          <Route exact path="/about/:colour" component={About} />
          <Route exact path="/hello" render={() => 
            <Hello name="Jakub"></Hello>
          } />
        </Switch>
      </div>
    </BrowserRouter>
  )
}

reactjs

React: Using react-spring intro

There's a nice animation library for react called react-springs. It uses hooks. So we'll be using hooks.

The first thing to look at is the useSpring custom hook. You pass it an object of your css properties (and whatever actually).

There's a sub property called from which takes an object of the initial position of the css property.

  const springProps = useSpring({ 
    left: "400px", 
    position: "absolute",
    from: { left: "0px" } 
  })

In this case we translate our left property from zero to four hundred. And we set the position to be absolute.

After we set this, we then pass the props into a animated.div component that understands them. The whole thing looks like this:

import { useSpring, animated } from 'react-spring'
...
function App () {
  const springProps = useSpring({ 
    left: "400px", 
    position: "absolute",
    from: { left: "0px" } 
  })
  return (
    <div>
      <animated.div style={springProps}>
        I will slide
      </animated.div>
    </div>
  );
}

And we thus animate.

react-spring is a physics based library but we can blissfully ignore that and specify a time in config:

  const springProps = useSpring({ 
    left: "400px", 
    position: "absolute",
    from: { left: "0px" },
    config: { duration: 500 }
  })

You'll also notice this animation starts straight away. We can define when it's run by passing, not an object, but a function to useSpring and getting back the previous props, and a method to set the props:

function App () {
  const [springProps, set] = useSpring(() => ({ 
    left: "0px", 
    position: "absolute"
  }))
  const click = () => {
    set({ left: "400px" })
  }
  return (
    <animated.div 
      style={springProps} 
      onClick={click}>
      I will slide
    </animated.div>
  );
}

I've left out the from part of what we pass to useSpring since the from is now defined, and the to part is now defined with the setter function.

PS. You can animate your components inside the animated.div or do const AnimatedThing = animated(Thing) and then do <AnimatedThing style="{springProps}"> but at the moment that means Thing must be a class component, not a functional components, for reasons that are beyond me.

reactjs

React: react-spring transitions tutorial

React-spring transitions let your transition items when they're added or removed from a list. Let's use them with react hooks.

Let's create an array of items (each has a key). An index variable which will be the successive keys. And two functions that will add or remove something from that list (we're using array slice to make new versions of the array so react see the change):

const [items, setList] = useState([
  {key: 1, item: "one"},
  {key: 2, item: "two"},
  {key: 3, item: "three"}
])
const [index, setIndex] = useState(4)
const addToList = () => {
  setIndex(index+1)
  var nItems = items.slice()
  nItems.push({key: index, item: "new"})
  setList(nItems) 
}
const removeFromList = () => {
  var nItems = items.slice()
  nItems.pop()
  setList(nItems) 
}

Next we pass these items to useTransition. And we'll specify where the keys are for this list of items (this is very importtant). And finally we'll specify the react-spring transitions state.

const transitions = useTransition(items, item => item.key, {
  initial: { transform: 'translate3d(0%, 0%,0)' },
  from: {  transform: 'translate3d(0%,-100%,0)' },
  enter: { transform: 'translate3d(0%, 0%,0)' },
  leave: { transform: 'translate3d(100%,0%,0)' }
})

initial is the initial position of the items. from is where they come from when they're added (100% above the final position in this case). enter is its resting place. And leave is where it will go when it's removed from the list (in our case we'll animate it off the screen)

Finally we render it like this:

<div>
  <button onClick={addToList}>add</button>
  <button onClick={removeFromList}>remove</button>
  {transitions.map(({ item, props, key }) =>
    <animated.div 
      key={key} 
      style={props}>
      <div>{item.item}</div>
    </animated.div>
  )}
</div>

We then map over transitions and show a animated.div, which takes in the app import props as style props and the key we defined in our list. We have our two buttons which add and remove items.

All the code looks like this:

import React, { useState } from 'react';
import { useTransition, animated } from 'react-spring'
...
function AThing2() {
  const [items, setList] = useState([
    {key: 1, item: "one"},
    {key: 2, item: "two"},
    {key: 3, item: "three"}
  ])
  const [index, setIndex] = useState(4)
  const addToList = () => {
    setIndex(index+1)
    var nItems = items.slice()
    nItems.push({key: index, item: "new"})
    setList(nItems) 
  }
  const removeFromList = () => {
    var nItems = items.slice()
    nItems.pop()
    setList(nItems) 
  }
  const transitions = useTransition(items, item => item.key, {
    initial: { transform: 'translate3d(0%, 0%,0)' },
    from: {    transform: 'translate3d(0%,-100%,0)' },
    enter: {   transform: 'translate3d(0%, 0%,0)' },
    leave: {   transform: 'translate3d(100%,0%,0)' }
  })
  return (
    <div>
      <button onClick={addToList}>add</button>
      <button onClick={removeFromList}>remove</button>
      {transitions.map(({ item, props, key }) =>
        <animated.div 
          key={key} 
          style={props}>
          <div>{item.item}</div>
        </animated.div>
      )}
    </div>
  )
}

Demo

reactjs

React: Custom hooks

Custom hooks are used to reuse logic. If you understand setState and useEffect then custom hooks are nothing special. Let's create one. They're just normal functions. They return a value too.

In our custom hook, we'll use useEffect to run a setTimeout when the component is rendered. It will set some state after a specified timeout. Therefore whatever uses this custom hook refuses this logic.

function useTimeout(timeout) {
  var timeoutHandler
  const [text, setText] = useState("Waiting...")
  useEffect(() => {
    timeoutHandler = setTimeout(() => setText("Waited!"), timeout)
    return () => {
      clearTimeout(timeoutHandler)
    }
  })
  return text
}

We can now refuse this logic in any component. For example:

function App () {
  const text = useTimeout(1000)
  return (
    <div>
      <div>{text}</div>
    </div>
  )
}

The {text} will change after one second from Waiting... to Waited!. There are better use cases.

reactjs

React: Using hooks

React created functional components for when you need a component that doesn't have state and now they've released hooks which allow you to use state in functional components. Such is life. They're nice in some extra ways too.

Instead of setting state in a component class's constructor, you use useState. You pass it an argument which will be the initial state. And it gives you back that value and the a function to set that state. You can use useState as many times as you want for as much state as you want. Got that? Good?

Instead of using componentDidMount etc you use useEffect. The first argument is a function. The second argument can be empty which means that function is run on every render. If it's [] it's run only on component mount. If it's [someValue] then that will only be run when someValue is changed. It's best to give an example at this point:

import React, { useState, useEffect } from 'react';
...
function App2 () {
  const [ count, setCount] = useState(0)
  const click = () => setCount(count+1)

  useEffect(() => {
    setCount(10)
  }, [])

  return (
    <div>
      <div>{count}</div>
      <button onClick={click}>Click</button>
    </div>
  );
}

useState(0) sets an initial count state. setCount can be used to set the state. useEffect is used to set the count state to 10 when the component mounts. In this case it's just used for demonstation purposes. In addition you can return a function from useEffect and that function will be run to clean up after the render or after the compontent unmounted if [] was passed to useEffect.

reactjs

Page 2 of 4
prev next
Click me