Reactjs UI 和业务逻辑分离

问题描述 投票:0回答:4

我是 React 新手,看着充满大量函数和变量初始化的组件以及 UI,我觉得眼睛很痛。可以分开吗?

而不是默认设置,如下所示。如何将业务逻辑分离到另一个文件中?

function MyComponent() {
    const [data, setData] = useState('');
    const someFunc = () => {
        //do something.
    };
    ... some 100-liner initializations

   return ( 
       ...
   )
}
javascript reactjs react-hooks separation-of-concerns
4个回答
91
投票

是的,这是可能的,这就是所谓的

Separation of concern

您可以如下创建组件结构。

MyComponentDirectory
 - useCustomHook
 - Component
 - helper

代码看起来像这样。

挂钩

const useCustomHook = () => {

    const [value, setValue] = useState('');
    const handleClick = (value) => {
        setValue(value)
        //do something.
    };
    ... some 100-liner initializations/business logic, states, api calls. 

    return {
        value, 
        handleClick,
        ... // Other exports you need. 
    } 
}

export default useCustomHook; 

组件

function MyComponent() {
   const {
       value, 
       handleClick, 
       ... // Other imports 
   } = useCustomHook() 

   return ( 
       <Element value={value} onClick={handleClick} />
   )
}

帮手

const doSomething = () => {}

编辑

这是使用

Separation of concern

的 React 计数器应用程序的详细示例

结构

Directory
- App
- Counter
- useCounter
- helper

应用程序组件

import Counter from "./Counter";
import "./styles.css";

export default function App() {
  return (
    <div className="App">
      <Counter />
    </div>
  );
}

计数器组件

import useCounter from "./useCounter";

const Counter = () => {
  const { count, increaseCount, decreaseCount } = useCounter();

  return (
    <div>
      <p>{count}</p>
      <div>
        <button onClick={increaseCount}>Increase</button>
        <button onClick={decreaseCount}>Decrease</button>
      </div>
    </div>
  );
};

export default Counter;

使用反钩

import { useState } from "react";
import numberWithCommas from "./helper";

const useCounter = () => {
  const [count, setCount] = useState(9999);

  const increaseCount = () => setCount(count + 1);
  const decreaseCount = () => setCount(count - 1);

  return {
    count: numberWithCommas(count),
    increaseCount,
    decreaseCount
  };
};

export default useCounter;

辅助功能

const numberWithCommas = (x) => {
  return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
};

export default numberWithCommas;

这是 Codesandbox

中的工作示例

注意:如果您创建一个简单的 Javascript util 函数而不是钩子,那么您将无法访问其他钩子以及该函数内的上下文。


5
投票

我自己使用的一种常见方法是将业务逻辑分离到自己的文件中

myComponentHelper.js

这也将使测试函数变得更容易,因为如果不将其作为参数传入并返回更改,它将无法使用和更改反应状态。

myComponent/
  myComponent.jsx
  myComponentHelper.js
  myComponentTest.js
// myComponent.js

import { someFunc } from './myComponentHelper';

function MyComponent() {
    const [data, setData] = useState('');
    
    const x = someFunc(data);

    return ( 
        ...
    )
}
// myComponentHelper.js

export const someFunc = (data) => {
    //do something.
    return something;
}
// myComponentTest.js

import { someFunc } from './myComponentHelper';

test("someFunc - When data is this - Should return this", () => {
    const data = {...};
    const result = someFunc(data);
    expect(result).toEqual("correct business data");
});

2
投票

可以通过各种不同的方式将业务逻辑分离到其他文件中。

  1. 创建一个helperFile.js,其中包含相应文件所需的逻辑或基本功能。
  2. 创建自定义挂钩。更多相关内容可以在官方文档中找到在此播放列表中 (参考最后的视频)
  3. 全局状态管理方式 - 其中contextAPIRedux用于分离状态和业务逻辑

0
投票

根据单一职责原则,使用自定义挂钩以简单的方式保持业务逻辑(如果需要,请在其中使用原型继承),要存储API调用,请使用Tanstack Query并使用Jotai(Atoms)存储全局数据。这个库非常容易学习和维护。

您现在不需要编写 Redux(action、reducers 和 store)、Redux 工具包和其他样板代码。即使您学习了这个概念,它在其他堆栈中也没有那么有用。

下面给出了示例片段。

const Counter = () => {
  const {sendCounterdata} = useCounterAPI() // TanstackQuery
  const [counter, setCounter] = useAtom(counterAtom); // Jotai atom

 // Custom hook
  const { increment, decrement, submit } =
   useCounter({setCounter, onSubmit: sendCounterdata});

  return (
    <>
      {counter}
      <Button onPress={increment}>Increment</Button>
      <Button onPress={decrement}>Decrement</Button>
      <Button onPress={submit}>Submit</Button>
    </>
  );
};

注意:React 团队建议对业务逻辑使用自定义挂钩而不是 HOC。

历史:React mixins => Redux Redcers => HOC => React hooks。

奖励:您可以轻松地为自定义挂钩“useCounter”编写单元测试。

© www.soinside.com 2019 - 2024. All rights reserved.