dimanche 13 mars 2022

React Class Component Separate UI & Business Logic

I am trying to separate UI and Logic in React class component with little bit of js. I know this could be done easily with custom hooks. But I need to do with class components.

I could make some progress, but it doesnot seem efficient, need your input.

App.view.js

import React from "react";
import Header from "../components/Header";
import ListWrapper from "../components/ListWrapper";
import SearchField from "../components/SearchField";
import UserCard from "../components/UserCard";
import AppController from "./App.controller";

class App extends React.Component {
  constructor() {
    super();
    this.state = { users: [], searchValue: "" };
    this.setState = this.setState.bind(this);
  }

  componentDidMount() {
    AppController(this.state, this.setState).fetchUsers();
  }

  render() {
    const filteredUsers = AppController(
      this.state,
      this.setState
    ).handleFilter();

    return (
      <div className="wrapper pb-12 bg-gray-100 mx-auto max-w-7xl">
        <Header heading="đŸ¶ Pets Rolodex" />
        <SearchField
          labelText="Search Pets"
          fieldId="pets-search-field"
          placeholderText="Enter name"
          searchValue={this.state.searchValue}
          handleChange={AppController(this.state, this.setState).handleChange}
          className="w-72"
        />
        <ListWrapper
          listData={filteredUsers}
          ListItem={UserCard}
          ListItemProp="user"
        />
      </div>
    );
  }
}

export default App;

App.controller.js

const AppController = (state, setState) => ({
  // Fetch Users info
  fetchUsers: () => {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then(res => res.json())
      .then(data => setState({ users: data }))
      .catch(error => console.error(error));
  },

  // Input Field Handler
  handleChange: event => {
    const { value } = event.target;
    setState({ searchValue: value });
  },

  // Filter Handler
  handleFilter: () => {
    const { searchValue, users } = state;
    if (searchValue === "") {
      return users;
    } else {
      return users.filter(usr =>
        usr.name.toLowerCase().includes(searchValue.toLowerCase())
      );
    }
  }
});

export default AppController;

This works fine. Codesandbox

But the issue is, this instantiates multiple objects from function calls AppController(this.state, this.setState) and this happens on every render(){...} It is like I creating and destroying function stored in memory.

What I tried

I moved function call to constructor like below:

  constructor() {
    super();
    this.state = { users: [], searchValue: "" };
    this.setState = this.setState.bind(this);
    this.controller = AppController(this.state, this.setState)
  }

and use this.controller everywhere in view.

But this seems to persist initial state (empty) into function execution context and all logic functions inside it never see a light of new state.

Thanks in advance for your input :)

Aucun commentaire:

Enregistrer un commentaire