我来自angular世界,在那里我可以提取逻辑到服务/工厂,并在我的控制器中使用它们。

我试图了解如何在React应用程序中实现相同的功能。

假设我有一个验证用户密码输入的组件(它的强度)。它的逻辑相当复杂,因此我不想把它写在组件中。

我应该把这个逻辑写在哪里?如果我在商店里使用助焊剂?还是有更好的选择?


当前回答

我需要一些可以在多个组件间共享的格式化逻辑,而作为Angular开发人员,我自然也倾向于使用服务。

我通过将其放在一个单独的文件中来共享逻辑

function format(input) {
    //convert input to output
    return output;
}

module.exports = {
    format: format
};

然后把它作为一个模块导入

import formatter from '../services/formatter.service';

//then in component

    render() {

        return formatter.format(this.props.data);
    }

其他回答

我也来自Angular,正在尝试React,目前,一个推荐的方法似乎是使用高阶组件:

高阶组件(HOC)是React中的一种高级技术 重用组件逻辑。hoc本身不是React API的一部分。 它们是React的组合特性中出现的一种模式。

假设你有input和textarea,想要应用相同的验证逻辑:

const Input = (props) => (
  <input type="text"
    style={props.style}
    onChange={props.onChange} />
)
const TextArea = (props) => (
  <textarea rows="3"
    style={props.style}
    onChange={props.onChange} >
  </textarea>
)

然后编写一个HOC来验证并设置包装组件的样式:

function withValidator(WrappedComponent) {
  return class extends React.Component {
    constructor(props) {
      super(props)

      this.validateAndStyle = this.validateAndStyle.bind(this)
      this.state = {
        style: {}
      }
    }

    validateAndStyle(e) {
      const value = e.target.value
      const valid = value && value.length > 3 // shared logic here
      const style = valid ? {} : { border: '2px solid red' }
      console.log(value, valid)
      this.setState({
        style: style
      })
    }

    render() {
      return <WrappedComponent
        onChange={this.validateAndStyle}
        style={this.state.style}
        {...this.props} />
    }
  }
}

现在这些hoc共享相同的验证行为:

const InputWithValidator = withValidator(Input)
const TextAreaWithValidator = withValidator(TextArea)

render((
  <div>
    <InputWithValidator />
    <TextAreaWithValidator />
  </div>
), document.getElementById('root'));

我创建了一个简单的演示。

编辑:另一个演示是使用props来传递一个函数数组,这样你就可以在hoc之间共享由多个验证函数组成的逻辑,比如:

<InputWithValidator validators={[validator1,validator2]} />
<TextAreaWithValidator validators={[validator1,validator2]} />

Edit2: React 16.8+提供了一个新特性Hook,这是另一种共享逻辑的好方法。

const Input = (props) => {
  const inputValidation = useInputValidation()

  return (
    <input type="text"
    {...inputValidation} />
  )
}

function useInputValidation() {
  const [value, setValue] = useState('')
  const [style, setStyle] = useState({})

  function handleChange(e) {
    const value = e.target.value
    setValue(value)
    const valid = value && value.length > 3 // shared logic here
    const style = valid ? {} : { border: '2px solid red' }
    console.log(value, valid)
    setStyle(style)
  }

  return {
    value,
    style,
    onChange: handleChange
  }
}

https://stackblitz.com/edit/react-shared-validation-logic-using-hook?file=index.js

如果你还在寻找像Angular这样的服务,你可以尝试react-rxbuilder库

您可以使用@Injectable来注册服务,然后您可以使用useService或CountService。在组件中使用服务

import { RxService, Injectable, useService } from "react-rxbuilder";

@Injectable()
export class CountService {
  static ins: CountService;

  count = 0;
  inc() {
    this.count++;
  }
}

export default function App() {
  const [s] = useService(CountService);
  return (
    <div className="App">
      <h1>{s.count}</h1>
      <button onClick={s.inc}>inc</button>
    </div>
  );
}

// Finally use `RxService` in your root component
render(<RxService>{() => <App />}</RxService>, document.getElementById("root"));

预防措施

取决于rxjs和typescript 不能在服务中使用箭头函数

我和你处境相同。在你提到的情况下,我将输入验证UI组件实现为一个React组件。

我同意验证逻辑本身的实现应该(必须)不耦合。因此,我会把它放在一个单独的JS模块中。

也就是说,对于不应该耦合的逻辑,在单独的文件中使用JS模块/类,并使用require/import将组件与“服务”解耦。

这允许独立地进行依赖注入和单元测试。

同样的情况:在做了多个Angular项目后转向React,没有一个简单的方法通过DI提供服务似乎是一个缺失的部分(抛开服务的细节不谈)。

使用context和ES7装饰器,我们可以接近:

https://jaysoo.ca/2015/06/09/react-contexts-and-dependency-injection/

似乎这些家伙在不同的方向上更进一步:

http://blog.wolksoftware.com/dependency-injection-in-react-powered-inversifyjs

还是觉得有违常理。在承担一个主要的React项目后,将在6个月的时间内重新审视这个答案。

编辑:6个月后回来,有了更多的React经验。考虑一下逻辑的本质:

它是否(仅)绑定到UI?将其移动到组件中(已接受的答案)。 它(只)与国家管理有关吗?移动到一个坦克。 两者都有关系?移动到单独的文件,在组件中通过选择器和坦克消费。

有些人还使用hoc进行重用,但对我来说,以上几乎涵盖了所有用例。另外,考虑使用鸭子来扩展状态管理,以保持关注点的独立性和以状态ui为中心。

在React世界中,我们有两种类型的逻辑:有状态的和无状态的。现在,这是开始React时要掌握的主要概念。这里我们更新的状态应该是更新UI,而不是Angular对dom的直接更新。两种类型的逻辑是:

That do not depend on state changes, i.e. static logic which doesn't need to re-render something based on state changes. For such cases just create regular js files and import them like a library or helper methods If you have some code that depends on state and u need to resuse it then two options - hocs and the newer hooks. Hooks are a bit hard to wrap our heads around but basically they would force their parent to rerender if their internal state changes so any stateful logic can be defined and reused in different components, and each hook instance would have its own isolated scope.

理解状态和声明性组件需要一点思维转变,但可以在评论中随意提出后续问题