简体   繁体   English

React Class 组件分离的 UI 和业务逻辑

[英]React Class Component Separate UI & Business Logic

I am trying to separate UI and Logic in React class component with little bit of js.我正在尝试使用少量 js 将 React class 组件中的 UI 和逻辑分开。 I know this could be done easily with custom hooks.我知道这可以通过自定义挂钩轻松完成。 But I need to do with class components.但我需要处理 class 个组件。

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 am creating and destroying function stored in memory.但问题是,这从 function 调用AppController(this.state, this.setState)实例化多个对象,这发生在每个render(){...}就像我正在创建和销毁存储在 memory 中的 function。

What I tried我试过的

I moved the function call to constructor like below:我将 function 调用移动到构造函数,如下所示:

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

and used this.controller everywhere in view.并在视图中到处使用this.controller

But this seems to persist initial state (empty) into function's execution context and all logic functions inside it never see a light of new state.但这似乎将初始 state(空)保留到函数的执行上下文中,并且其中的所有逻辑函数都看不到新的 state。

Thanks in advance for your input:)提前感谢您的输入:)

You can refactor the AppController to class and pass the component instance to its constructor.您可以将AppController重构为 class 并将组件实例传递给其构造函数。

Eg例如

App.tsx : App.tsx

import React from "react";
import ReactDOM from "react-dom";
import Controller from "./controller";

class App extends React.Component<any, { users: any[]; searchValue: string }> {
  controller: InstanceType<typeof Controller>;
  constructor(props) {
    super(props);
    this.state = { users: [], searchValue: "" };
    this.controller = new Controller(this);
  }

  componentDidMount() {
    this.controller.fetchUsers();
  }

  render() {
    const filteredUsers = this.controller.handleFilter();
    return (
      <ul>
        {filteredUsers.map((user) => (
          <li key={user.key}>{user.name}</li>
        ))}
      </ul>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("container"));

controller.ts : controller.ts :

class Controller {
  compInstance;
  constructor(compInstance) {
    this.compInstance = compInstance;
  }
  // Fetch Users info
  fetchUsers() {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then((res) => res.json())
      .then((data) => this.compInstance.setState({ users: data }))
      .catch((error) => console.error(error));
  }

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

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

export default Controller;

codesandbox 代码沙盒

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM