NewFiveFour | Blog | Portfolio


Android: Deep linking basics

Let's say you have an Activity in your manifest that has VIEW action and that's in the DEFAULT and BROWSABLE category:

<activity android:name=".TwoActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <category android:name="android.intent.category.BROWSABLE"/>
        <data android:scheme="https"
            android:host="someurl.com"
            android:path="/new" />
    </intent-filter>
</activity>

Note we have a new data tag. It has a scheme and a host and a path. It points to a URL.
 
Now if you make a <a> link to https://someurl.com/new and press on it in your browser, it will open the above activity.
 
If you want to open the deep link programmatically you can:

Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://someurl.com/new"));
startActivity(intent);

android


React: Animating component transition with react-spring and react-router

We can animate component transitions with react-spring's transitions. We'll use its react hooks implementation.
 
This is an explanation of: https://codesandbox.io/embed/jp1wr1867w
 
Let's first define our components along with a helper function to give it a full height style and background colour:
 
We'll use react-router's Link to go to a new component.

var pageStyle = (colour) => ({ height: "100%", backgroundColor: colour })

function A() {
  return <Link to="/b"><div style={pageStyle("lightblue")}>A</div></Link>
}
function B() {
  return <Link to="/c"><div style={pageStyle("pink")}>B</div></Link>
}
function C() {
  return <Link to="/a"><div style={pageStyle("lightgreen")}>C</div></Link>
}

We're going to use react's useContext hook and use react-router's __ReactContext. This gives us access to the current browser location. We'll use this to tell react-spring when it needs to transitions. We'll use this location, and location.pathname as the key for react-spring's transition:

const { location } = useContext(__RouterContext)
const transitions = useTransition(location, location => location.pathname, {
  initial: { transform: 'translate3d(0, 0%,0)'},
  from:    { transform: 'translate3d(0, 80%,0)'},
  enter:   { transform: 'translate3d(0, 0%,0)'},
  leave:   { transform: 'translate3d(0, -90%,0)'}
})

Finally we'll map over this transitions array, passing the key and props to animated.div and having the Switch within that. The animated.div must have absolute positioning to be able to animate it around the page.
 
Here's the whole thing:

import React, { useContext } from 'react';
import { useTransition, animated } from 'react-spring'
import { Route, BrowserRouter, Link, Switch, __RouterContext } from 'react-router-dom';
...
function App() {
  return (
    <BrowserRouter>
      <Home />
    </BrowserRouter>
  )
}

function Home() {
  const { location } = useContext(__RouterContext)
  const transitions = useTransition(location, location => location.pathname, {
    initial: { transform: 'translate3d(0, 0%,0)'},
    from: { transform: 'translate3d(0, 80%,0)'},
    enter: { transform: 'translate3d(0, 0%,0)'},
    leave: { transform: 'translate3d(0, -90%,0)'}
  })
  return (
    transitions.map(({ item, props, key}) => (
      <animated.div 
        style={{...props, position: "absolute", height: "100%", width: "100%"}} 
        key={key}>
        <Switch location={item}>
          <Route exact path="/" component={A} />
          <Route exact path="/a" component={A} />
          <Route exact path="/b" component={B} />
          <Route exact path="/c" component={C} />
        </Switch>
      </animated.div>
    ))
  )
}

var pageStyle = (colour) => ({ height: "100%", backgroundColor: colour })

function A() {
  return <Link to="/b"><div style={pageStyle("lightblue")}>A</div></Link>
}
function B() {
  return <Link to="/c"><div style={pageStyle("pink")}>B</div></Link>
}
function C() {
  return <Link to="/a"><div style={pageStyle("lightgreen")}>C</div></Link>
}

reactjs javascript


React: useReducer guide

React hooks introduced useReducer. This is an alternative to useState. And it comes from the redux world.
 
You give the reducer some state. Then based on actions (can be just names like 'add') it changes the state.
 
Let's first make a todo list example without a reducer, then afterward with a reducer, so we can see the difference.

Version without a reducer


function Todos() {
  const [textInput, setTextInput] = useState("")
  const [todos, setTodos] = useState([ 
    { item: "example1", done: false }, 
    { item: "example2", done: false }])
  const addTodo = () => {
    const newTodos = todos.slice()
    newTodos.push({ item: textInput, done: false })
    setTodos(newTodos)
  }
  const deleteNote = (index) => {
    const newTodos = todos.slice()
    newTodos.splice(index, 1)
    setTodos(newTodos)
  }
  const tickNote = (index) => {
    const newTodos = todos.slice()
    newTodos[index].done = !newTodos[index].done
    setTodos(newTodos)
  }
  return (
    <div>
      <input value={textInput} onChange={(e) => setTextInput(e.target.value)} />
      <button onClick={addTodo}>add</button>
      <div>
        {todos.map((item, i) => 
          <div key={i}>
            {item.item}
            <button onClick={() => tickNote(i)}>done? {""+item.done}</button>
            <button onClick={() => deleteNote(i)}>x</button>
          </div>
        )}
      </div>
    </div>
  )
}

We set two pieces of state. The first is to collect the <input> value. The second is our list of todo items.
 
Then the functions alter the todo list and update the state, and thus the user interface.
 
Now let's look at the version with a reducers.

Version with a reducer


The first thing note is that we have global state that includes both the todos and the input text:

var initialList = {
  textInput: "",
  todos: [
    { item: "example1", done: false }, 
    { item: "example2", done: false }
  ]
}

This is then passed to the reducer as the second argument -- giving it initial data:

  var [state, dispatch] = useReducer(..., 
    initialList)

The useReducer returns two things. The updated state and a dispatcher. The dispatcher will be used to send 'actions', e.g. dispatch(['delete', i]).
 
How do we handle these 'actions'? It's all in the first argument to useReducer:

var [state, dispatch] = useReducer((state, [action, payload]) => {
  switch(action) {
    case 'updateText': 
      return {...state, textInput: payload }
    case 'add': 
      state.todos.push({ item: state.textInput, done: false })
      return { ...state, textInput: "" }
    case 'delete': 
      state.todos.splice(payload, 1)
      return { ...state }
    case 'mark': 
      state.todos[payload].done = !state.todos[payload].done
      return { ...state }
    default: 
      throw new Error("bad action")
  }
}, initialList)

The first argument of useReducer takes a function. This function takes two parameters: the existing state and the argument to dispatch(...). (I'm destructuring this parameter for ease of use).
 
Then inside this function you use a switch statement with the 'action' you passed. And in our case something called a 'payload' which is the second item in the array that I will pass to dispatch.
 
So where is dispatch called? In our HTML:

<div>
  <input value={state.textInput} onChange={(e) => dispatch(["updateText", e.target.value])} />
  <button onClick={() => dispatch(['add'])}>add</button>
  <div>
    {state.todos.map((item, i) => 
      <div key={i}>
        {item.item}
        <button onClick={() => dispatch(['mark', i])}>done? {""+item.done}</button>
        <button onClick={() => dispatch(['delete', i])}>x</button>
      </div>
    )}
  </div>
</div>

Altogether our code looks like this:

function TodosReducer() {
  var initialList = {
    textInput: "",
    todos: [
      { item: "example1", done: false }, 
      { item: "example2", done: false }
    ]
  }
  var [state, dispatch] = useReducer((state, [action, payload]) => {
    switch(action) {
      case 'updateText': 
        return {...state, textInput: payload }
      case 'add': 
        state.todos.push({ item: state.textInput, done: false })
        return { ...state, textInput: "" }
      case 'delete': 
        state.todos.splice(payload, 1)
        return { ...state }
      case 'mark': 
        state.todos[payload].done = !state.todos[payload].done
        return { ...state }
      default: 
        throw new Error("bad action")
    }
  }, initialList)
  
  return (
    <div>
      <input value={state.textInput} onChange={(e) => dispatch(["updateText", e.target.value])} />
      <button onClick={() => dispatch(['add'])}>add</button>
      <div>
        {state.todos.map((item, i) => 
          <div key={i}>
            {item.item}
            <button onClick={() => dispatch(['mark', i])}>done? {""+item.done}</button>
            <button onClick={() => dispatch(['delete', i])}>x</button>
          </div>
        )}
      </div>
    </div>
  )
}

reactjs javascript


React: Context tutorial

Instead of passing data and functions around as props around you can use a context.
 
But first let's look an example app that doesn't use context. It uses props to communicate between components.
 
First we have a UserInfo component that displays a name:

function UserInfo({ name }) {
  return (
    <div>Your name is {name}</div>
  )
}

Then we have a ChooseUsername that on onChange in an input element calls a function that's passed in as a prop.

function ChooseUsername({ onChooseUsername }) {
  return (
    <div>
      <input placeholder="username" 
        onChange={(e) => onChooseUsername(e.target.value) } />
    </div>
  )
}

Finally we have the App component that threads those two components together: once ChooseUsername edits its input field then a function is called on App that sets some new state, which in turn updates the UserInfo component:

class App extends React.Component {
  state = {
    name: "Blank"
  }

  setName = (newName) => {
    this.setState({
      name: newName
    })
  }

  render() {
    return (
      <div>
        <ChooseUsername onChooseUsername={this.setName}></ChooseUsername>
        <hr />
        <UserInfo name={this.state.name}></UserInfo>
      </div>
    )  
  }
}

Now let's do the same again but with a react context.
 
Let's first look at our ChooseUsername and UserInfo components. I've given them a version 2 name.

function UserInfo2() {
  const state = useContext(App2Context);
  return (
    <div>Your name is {state.name}</div>
  )
}

function ChooseUsername2() {
  const state = useContext(App2Context);
  return (
    <div>
      <input placeholder="username" 
        onChange={(e) => state.onChooseUsername(e.target.value) } />
    </div>
  )
}

They no longer take in props. They get noth the name and onChooseUsername from the context that they get from useContext(App2Context). So what is App2Context? It's fairly simple:

const App2Context = React.createContext(null);

It contains no data at the moment. We want it to contain the state for our app:

 this.state = {
    name: "Blank",
    onChooseUsername: (newName) => {
      this.setState({
        name: newName
      })
    }
  } 

(Note I've put onChooseUsername in the state so the components can use it)
 
And we make the App2Context have this state through <App2Context.Provider>.
 
Let's look at our App2 class which uses the context:
 

const App2Context = React.createContext(null);

class App2 extends React.Component {
  state = {
    name: "Blank",
    onChooseUsername: (newName) => {
      this.setState({
        name: newName
      })
    }
  }
  render() {
    return (
      <App2Context.Provider value={this.state}>
        <ChooseUsername2></ChooseUsername2>
        <hr />
        <UserInfo2></UserInfo2>
      </App2Context.Provider>
    )  
  }
}

So UserInfo2 and ChoseUsername2 will use the context that's defined by <App2Context.Provider value={this.state}>. And when we call the onChooseUsername function it will update the state, and thus to context, and thus rerender the components in the tree.
 
So, why do this? Because passing around new props every time you add a new variable or function to your state is annoying.

reactjs javascript


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 javascript


Page 2 of 95
prev next

Portfolio