Categories
React Hooks

Top React Hooks — States and Requests

Hooks contains our logic code in our React app.

We can create our own hooks and use hooks provided by other people.

In this article, we’ll look at some useful React hooks.

Hookstate

We can use the Hookstate hook to change global and local state in our app.

To use it, we run:

npm install --save @hookstate/core

or:

yarn add @hookstate/core

to install it.

Then we can manage global state by writing:

import React from "react";
import { createState, useState } from "@hookstate/core";
const globalState = createState(0);

export default function App() {
  const state = useState(globalState);
  return (
    <>
      <p>Counter value: {state.get()}</p>
      <button onClick={() => state.set(p => p + 1)}>Increment</button>
    </>
  );
}

We create a global state object with the createState function and then pass it into the Hookstate’s useState hook.

Then we can use get and set to get and set the state respectively.

To change local state, we can write:

import React from "react";
import { useState } from "@hookstate/core";

export default function App() {
  const state = useState(0);
  return (
    <>
      <p>Counter value: {state.get()}</p>
      <button onClick={() => state.set(p => p + 1)}>Increment</button>
    </>
  );
}

The only difference is that we pass the state value straight into the useState hook.

States can be nested.

For example, we can write:

import React from "react";
import { useState, self } from "@hookstate/core";

export default function App() {
  const state = useState([{ name: "Untitled" }]);

console.log(state);
  return (
    <>
      {state.map((task, index) => (
        <p>
          {task.name.get()} {index}
        </p>
      ))}
      <button onClick={() => state[self].merge([{ name: "Untitled" }])}>
        add task
      </button>
    </>
  );
}

We use the useState hook with an array.

To add new value to the array, we use the state[self] object’s merge method to add an entry to it.

Then we can get the entry by using the property’s get method as we did in the map callback.

We can also add scoped, async, and recursive states.

We can use the @jzone/react-request-hook to help us make requests easier.

We can install it by running:

npm install @jzone/react-request-hook

or:

yarn add @jzone/react-request-hook

Then we can use it by writing:

import React from "react";
import useFetchData from "@jzone/react-request-hook";
import axios from "axios";

export default function App() {
  const [{ data, isLoading, error }, fetchData] = useFetchData(data =>
    axios.get("https://api.agify.io/?name=michael", { params: data })
  );

  React.useEffect(() => {
    fetchData();
  }, [fetchData]);

  if (!data) {
    return !error ? <div>loading...</div> : <div>error</div>;
  }

  return (
    <div>
      <p>{JSON.stringify(data)}</p>
    </div>
  );
}

We imported the useFetchData hook to import the hook.

Also, we installed Axios to use that as an HTTP client.

Then we use the fetchData function returned by the hook to get the data.

The data has the response data.

So we can render that the way we want.

It also returns the isLoading state to indicate loading.

error has the error.

We can customize it for other kinds of requests.

Conclusion

Hookstate is a useful hook for managing states.

@jzone/react-request-hook is a hook that lets us get data easier.

Categories
React Hooks

Top React Hooks — State Management

Hooks contains our logic code in our React app.

We can create our own hooks and use hooks provided by other people.

In this article, we’ll look at some useful React hooks.

Conuse

Conuse is a state management library that lets us share state between components with the Context API.

We can use it by running:

npm i conuse

or:

yarn add conuse

to install it.

Then we can use it by writing:

import React, { useState } from "react";
import createConuse from "conuse";

const useCounter = () => {
  const [count, setCount] = useState(0);
  const increment = () => setCount(prevCount => prevCount + 1);
  return { count, increment };
};

const { ConuseProvider, useConuseContext } = createConuse({
  counter: useCounter
});

function Button() {
  const { increment } = useConuseContext("counter");
  return <button onClick={increment}>increment</button>;
}

function Count() {
  const { count } = useConuseContext("counter");
  return <span>{count}</span>;
}

export default function App() {
  return (
    <ConuseProvider>
      <Count />
      <Button />
    </ConuseProvider>
  );
}

We have our useCounter ook which returns the count state and the increment function to update the count.

Then we use the createConuse function to create our context provider and the hook to use the context.

We pass our useCounter hook into the object and set that as the value of property.

Then we can use the context with the given name by using the useConuseContext hook with the given string in the Button component

We use the increment function which is the same one we returned in useCounter .

Likewise, the Count component gets the state from the same useConuseContext hook and render the count.

Then in App , we [put everything together with the ConuseProvider wrapping around everything.

ConuseProvider is the context provider, so that’ll be used for sharing the states.

Easy Peasy

Easy Peasy is a package that lets us manage state easily for our React app.

To install it, we run:

npm install easy-peasy

to install it.

Then we can use it by writing:

import React, { useState } from "react";
import {
  createStore,
  action,
  useStoreState,
  useStoreActions,
  StoreProvider
} from "easy-peasy";

const store = createStore({
  todos: {
    items: ["eat", "drink", "sleep"],
    add: action((state, payload) => {
      state.items.push(payload);
    })
  }
});

function TodoList() {
  const todos = useStoreState(state => state.todos.items);
  const add = useStoreActions(actions => actions.todos.add);
  return (
    <div>
      {todos.map((todo, idx) => (
        <div key={idx}>{todo}</div>
      ))}
      <button onClick={() => add("new task")}>add</button>
    </div>
  );
}

export default function App() {
  return (
    <StoreProvider store={store}>
      <TodoList />
    </StoreProvider>
  );
}

We create a store object with the createStore function.

The todos is the state.

items has the items.

add is an action that we created.

We create an action with the action function.

It has a callback to update the state.

We get the state from the state parameter and do stuff to it.

Then we created the TodoList component.

It uses the useStoreState hook to get the state.

And he useStoreActions get the action we can use.

We pass in a value to add to set the payload parameter’s value.

Then in App , we wrap our app with the StoreProvider .

We pass in our store to it so we can get and set its states.

Then we put the TodoList inside it to let us get and set the state.

Conclusion

Conuse and Easy Peasy are both state management libraries we can use in our React app.

Categories
React Hooks

Top React Hooks — State and API

Hooks contains our logic code in our React app.

We can create our own hooks and use hooks provided by other people.

In this article, we’ll look at some useful React hooks.

Nice Hooks

Nice Hooks is a set of hooks that does various things.

To install it, we run:

npm install nice-hooks

The useLifeCycle hook lets us add lifecycle methods as we do with class components.

For instance, we can write:

import React from "react";
import { useLifeCycle } from "nice-hooks";

export default function App() {
  useLifeCycle({
    didMount() {
      console.log("mounted");
    },

    willUnmount() {
      console.log("willUnmount");
    },

    didUpdate() {
      console.log("didUpdate");
    },

    didMountAndWillUnmount: [
      {
        didMount() {
          console.log("didMount");
        },
        willUnmount() {
          console.log("willUnmount");
        }
      },
      {
        didMount() {
          console.log("didMount");
        },
        willUnmount() {
          console.log("willUnmount");
        }
      }
    ]
  });

  return <div />;
}

We use the useLifeCycle hook to add the lifecycle hooks to our components.

The useInstanceVar hook lets us create instance variables in our component.

For example, we can write:

import React from "react";
import { useInstanceVar, useSingleState } from "nice-hooks";

export default function App() {
  const [getIntervalVal, setIntervalVal] = useInstanceVar(null);
  const [state, setState] = useSingleState({ count: 0 });

  function start() {
    const interval = setInterval(
      () => setState({ count: state.count + 1 }),
      1000
    );
    setIntervalVal(interval);
  }

  function stop() {
    const interval = getIntervalVal();
    interval && clearInterval(interval);
  }

  return (
    <div>
      <p>{state.count}</p>
      <button onClick={start}>Start</button>
      <button onClick={stop}>Stop</button>
    </div>
  );
}

We use the useInstanceVar hook to create our getter and setter for our instance variable.

In the start function, we called setIntervalVal to set the instance variable value to the timer.

In the setInterval callback, we update the count state that’s returned from useSingleState .

In stop , we called getIntervalVal to get the state we set and call clearInterval on it if it’s set.

promise-hook

The promise-hook library lets us fetch data with a hook.

To install it, we install it by running:

yarn add promise-hook

or:

npm i promise-hook --save

Then we can use it by writing:

import React from "react";
import { usePromise } from "promise-hook";

const fetchName = () =>
  fetch(`https://api.agify.io/?name=michael`).then(res => res.json());

export default function App() {
  const { isLoading, data } = usePromise(fetchName, { resolve: true });

  return isLoading ? <div>Loading...</div> : <div>{JSON.stringify(data)}</div>;
}

We defined the fetchName function to get data from our app.

We passed that into the usePromise hook to get the data.

resolve means that we get data when the component mounts.

The isLoading state indicates whether data is loading or not.

data has the data.

We can pass arguments by writing:

import React from "react";
import { usePromise } from "promise-hook";

const fetchName = name =>
  fetch(`https://api.agify.io/?name=${name}`).then(res => res.json());

const Name = ({ name }) => {
  const { isLoading, data } = usePromise(() => fetchName(name), {
    resolve: true,
    resolveCondition: [name]
  });

  return isLoading ? <div>Loading...</div> : <div>{JSON.stringify(data)}</div>;
};

export default function App() {
  return <Name name="james" />;
}

We get the name prop and then pass that into the fetchName function.

resolveCondition has the value to watch for when the API is called.

Conclusion

Nice Hooks lets us manage state in various ways.

The promise-hook library lets us fetch data with a hook.

Categories
React Hooks

Top React Hooks — Refs, Redux, and Async

Hooks contains our logic code in our React app.

We can create our own hooks and use hooks provided by other people.

In this article, we’ll look at some useful React hooks.

reactive-react-redux

The reactive-react-redux library is an alternative library to React-Redux for using Redux stores in our React app.

To use it, we install it by running:

npm install reactive-react-redux

Then we can use it by writing:

import React from "react";
import { createStore } from "redux";
import { Provider, useDispatch, useTrackedState } from "reactive-react-redux";

const initialState = {
  count: 0
};

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case "increment":
      return { ...state, count: state.count + 1 };
    case "decrement":
      return { ...state, count: state.count - 1 };
    case "setText":
      return { ...state, text: action.text };
    default:
      return state;
  }
};

const store = createStore(reducer);

const Counter = () => {
  const state = useTrackedState();
  const dispatch = useDispatch();
  return (
    <div>
      <span>Count: {state.count}</span>
      <button type="button" onClick={() => dispatch({ type: "increment" })}>
        increment
      </button>
      <button type="button" onClick={() => dispatch({ type: "decrement" })}>
        decrement
      </button>
    </div>
  );
};

export default function App() {
  return (
    <Provider store={store}>
      <Counter />
    </Provider>
  );
}

We have our initialState constant with the initial state.

Our reducer is a Redux reducer.

The store is created with the createStore function from Redux to create our store from the reducer .

In the Counter component, we use the useTrackedState hook to get the state.

And we use the useDispatch hook to get the dispatch function to let us dispatch our action to the reducer.

Then in App , we use the Provider with the store prop set to our store to let us use it as a data store.

Provider , useTrackedState , and useDispatch are from reactive-react-redux.

We can also select values from a state and do more.

React-async-hook

React-async-hook is a library to help us make API calls easier.

To install it, we run;

yarn add react-async-hook

or:

npm install react-async-hook --save

Then we can use it by writing:

import React from "react";
import { useAsync } from "react-async-hook";

const fetchName = async name =>
  (await fetch(`https://api.agify.io/?name=${name}`)).json();

export default function App() {
  const person = useAsync(fetchName, ["michael"]);
  return (
    <div>
      {person.loading && <div>Loading</div>}
      {person.error && <div>Error</div>}
      {person.result && (
        <div>
          <div>{JSON.stringify(person.result)}</div>
        </div>
      )}
    </div>
  );
}

We created the fetchName function to get our data.

Then we use the useAsync hook with it and the value to pass into the parameter to make the API call.

Then person has the loading , error , and result properties.

loading indicates whether the data is loading.

error indicates the error state.

result has the response body.

react-context-refs

The react-context-refs library lets us get React refs via a context.

We can install it by running:

npm i react-context-refs

Then we can use it by writing:

import React from "react";
import { useContextRef } from "react-context-refs";

const Input = ({ value, onChange, hasError }) => {
  const setRef = useContextRef({ hasError });

  return (
    <input
      style={hasError ? { backgroundColor: "orange" } : {}}
      ref={setRef}
      value={value}
      onChange={onChange}
    />
  );
};

export default function App() {
  const [val, setVal] = React.useState("");

  return (
    <div>
      <Input value={val} onChange={e => setVal(e.target.value)} hasError />
    </div>
  );
}

We pass in the hasError value to the useContextRef hook so that we can pass the returned value to the ref.

Conclusion

reactive-react-redux is an alternative for React-Redux.

React-async-hook lets us get data asynchronously.

react-context-refs lets us pass things to the ref via a context.

Categories
React Hooks

Top React Hooks — Network, Dimensions, and Scroll

Hooks contains our logic code in our React app.

We can create our own hooks and use hooks provided by other people.

In this article, we’ll look at some useful React hooks.

@rehooks/network-status

The @rehooks/network-status hook lets us get the network status in our React app.

To use it, we run:

yarn add @rehooks/network-status

Then we can use the useNetworkStatus hook to get the network information:

import React from "react";
import useNetworkStatus from "@rehooks/network-status";

export default function App() {
  const connection = useNetworkStatus();
  return (
    <div>
      <div>downlink: {connection.downlink}</div>
      <div>effectiveType: {connection.effectiveType}</div>
      <div>rtt: {connection.rtt}</div>
      <div>saveData: {connection.saveData ? "yes" : "no"}</div>
    </div>
  );
}

downlink has the upload speed.

effectiveType hs the connection type.

rtt is the round trip delay, which is the length of time it takes for a single to be sent plus the length of time it takes for the signal to be acknowledged.

@rehooks/online-status

@rehooks/online-status is a package to get the online status of an app.

It listens to online or offline events to get the status.

To install it, we can run:

yarn add @rehooks/online-status

Then we can use it by writing:

import React from "react";
import useOnlineStatus from "@rehooks/online-status";

export default function App() {
  const onlineStatus = useOnlineStatus();
  return (
    <div>
      <h1>{onlineStatus ? "Online" : "Offline"}</h1>
    </div>
  );
}

We can use the useOnlineStatus hook to get the online status of our app.

@rehooks/window-scroll-position

We can use the @rehooks/window-scroll-position hook to watch the scroll position in our app.

To install the package, we run:

yarn add @rehooks/window-scroll-position

Then we can use the package buy writing:

import React from "react";
import useWindowScrollPosition from "@rehooks/window-scroll-position";

export default function App() {
  const options = {
    throttle: 100
  };
  let position = useWindowScrollPosition(options);
  return (
    <>
      <div style={{ position: "fixed" }}>{JSON.stringify(position)}</div>
      {Array(1000)
        .fill()
        .map((_, i) => (
          <p>{i}</p>
        ))}
    </>
  );
}

We use the useWindowScrollPosition hook to watch for scroll position.

We also pass in an option to throttle the position watching.

Then when we scroll, we’ll see the x and y properties of position change.

@rehooks/window-size

We can use the @rehooks/window-size package to watch for window size changes.

To install it, we run:

yarn add @rehooks/window-size

Then we can use it by writing:

import React from "react";
import useWindowSize from "@rehooks/window-size";

export default function App() {
  let windowSize = useWindowSize();

  return (
    <>
      <div>{JSON.stringify(windowSize)}</div>
    </>
  );
}

We then use the useWindowSize hook to get the window dimensions.

innerHeight has the interior height with the horizontal scroll bar’s height in pixels.

innerWidth has the interior width of the window with the vertical scrollbar in pixels.

outerHeight has the height of the whole browser window in pixels.

outerHeight has the width of the whole browser window in pixels.

They both include sidebars and other borders.

Conclusion

We can get network status, scroll position, and window size with various hooks.