DEV Community

Cover image for React Design Patterns~High Order Components/ Data Updating~
Ogasawara Kakeru
Ogasawara Kakeru

Posted on

React Design Patterns~High Order Components/ Data Updating~

・src/server.js

let users = [
  {
    id: "1",
    name: "Smith",
    age: 55,
    country: "United Kingdom",
    magazines: ["VOGUE-UK", "ELLE"],
  },
  {
    id: "2",
    name: "Michele",
    age: 71,
    country: "United States",
    magazines: ["VOGUE-US", "ELLE"],
  },
  {
    id: "3",
    name: "John",
    age: 43,
    country: "Canada",
    magazines: ["VOGUE-CA", "ELLE"],
  },
];
app.get("/users/:id", (req, res) => {
  const { id } = req.params;
  res.json(users.find((user) => user.id === id));
});

app.post("/users/:id", (req, res) => {
  const { id } = req.params;
  const { user: editedUser } = req.body;

  users = users.map((user) => (user.id === id ? editedUser : user));

  res.json(users.find((user) => user.id === id));
});

let SERVER_PORT = 8080;
app.listen(SERVER_PORT, () =>
  console.log(`Server is listening on port: ${SERVER_PORT}`)
);
Enter fullscreen mode Exit fullscreen mode

・This file is executed on the server with a command like "node server.js".

・Install Express.js by running a command like "npm install express" if necessary

・If "Server listening on port: 8080" is displayed on the terminal,
means that the server has been successfully connected.

・You can get user by using app.get function.

・You can update user by using app.post function.

・src/components/user-form.jsx

import { includeUpdatableResource } from "./include-updatable-resource";

export const UserInfoForm = includeUpdatableResource(
  ({ user, onChangeUser, onPostUser, onResetUser }) => {
    const { name, age } = user || {};

    return user ? (
      <>
        <label>
          Name:
          <input
            value={name}
            onChange={(e) => onChangeUser({ name: e.target.value })}
          />
        </label>
        <label>
          Age:
          <input
            type="number"
            value={age}
            onChange={(e) => onChangeUser({ age: Number(e.target.value) })}
          />
        </label>
        <button onClick={onResetUser}>Reset</button>
        <button onClick={onPostUser}>Save</button>
      </>
    ) : (
      <h3>Loading...</h3>
    );
  },
  "/users/2",
  "user"
);

Enter fullscreen mode Exit fullscreen mode

This component displays name, age as user information.

・include-updatable-resource.jsx

import axios from "axios";
import React, { useEffect, useState } from "react";

const toCapital = (str) => str.charAt(0).toUpperCase() + str.slice(1);

export const includeUpdatableResource = (
  Component,
  resourceUrl,
  resourceName
) => {
  return (props) => {
    const [initialResource, setInitialResource] = useState(null);
    const [resource, setResource] = useState(null);

    useEffect(() => {
      (async () => {
        const response = await axios.get(resourceUrl);
        setInitialResource(response.data);
        setResource(response.data);
      })();
    }, []);

    const onChange = (updates) => {
      setResource({ ...resource, ...updates });
    };

    const onPost = async () => {
      const response = await axios.post(resourceUrl, {
        [resourceName]: resource,
      });
      setInitialResource(response.data);
      setResource(response.data);
    };

    const onReset = () => {
      setResource(initialResource);
    };

    const resourceProps = {
      [resourceName]: resource,
      [`onChange${toCapital(resourceName)}`]: onChange,
      [`onPost${toCapital(resourceName)}`]: onPost,
      [`onReset${toCapital(resourceName)}`]: onReset,
    };

    return <Component {...props} {...resourceProps} />;
  };
};

Enter fullscreen mode Exit fullscreen mode

・This component is a High Order Component.

・This component retrieves user information with axios on the server.

・This component updates user information with axios on the server.

・This component returns a component received as props, passing some props and user , onChangeUser, onPostUser, onResetUser as user props.

・src/App.js

import { UserInfoForm } from "./components/user-form";

function App() {
  return (
    <>
      <UserInfoForm />
    </>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

・This component returns the UserInfoForm component .

Image description

Top comments (0)