programing

React 응용 프로그램에 서비스 있음

muds 2023. 3. 12. 11:27
반응형

React 응용 프로그램에 서비스 있음

저는 서비스/공장으로의 논리를 추출하여 컨트롤러에서 소비할 수 있는 각진 세상에서 살고 있습니다.

리액트 어플리케이션에서도 같은 것을 실현하는 방법을 이해하려고 합니다.

예를 들어 사용자의 패스워드 입력을 검증하는 컴포넌트가 있다고 합시다(그것은 강점입니다).논리가 매우 복잡하기 때문에 직접 컴포넌트에 쓰고 싶지 않습니다.

이 논리는 어디에 써야 할까요?가게에서 플럭스를 사용한다면?아니면 더 좋은 방법이 있을까요?

Angular 서비스가 컨텍스트에 의존하지 않는 메서드 세트를 제공하는 개체일 뿐이라는 것을 알게 되면 이 문제는 매우 단순해집니다.Angular DI 메커니즘 때문에 더 복잡해 보여요DI는 인스턴스의 작성과 유지보수를 담당하기 때문에 편리하지만 실제로는 필요하지 않습니다.

Axios라는 이름의 인기 있는 AJAX 라이브러리를 생각해 보십시오(아마 들어보셨을 것입니다).

import axios from "axios";
axios.post(...);

서비스 역할을 하지 않나요?특정 로직을 담당하는 일련의 메서드를 제공하며 메인 코드와 독립적입니다.

이 예에서는 입력의 유효성을 확인하기 위한 격리된 메서드 세트(예: 비밀번호 강도 확인)를 작성했습니다.일부에서는 이러한 방법을 컴포넌트에 넣자고 제안했는데, 이는 명백히 안티 패턴입니다.검증에 XHR 백엔드 콜의 발신과 처리 또는 복잡한 계산이 포함되는 경우는 어떻게 됩니까?이 논리를 마우스 클릭 핸들러 및 기타 UI 관련 자료와 함께 사용할 수 있습니까?말도 안돼.컨테이너/HOC 접근법에서도 마찬가지입니다.값이 숫자에 포함되어 있는지 확인하는 메서드를 추가하기 위해 컴포넌트를 래핑하시겠습니까?부탁이야.

'ValidationService.js'라는 이름의 새 파일을 생성하여 다음과 같이 구성합니다.

const ValidationService = {
    firstValidationMethod: function(value) {
        //inspect the value
    },

    secondValidationMethod: function(value) {
        //inspect the value
    }
};

export default ValidationService;

다음으로 컴포넌트에서 다음을 수행합니다.

import ValidationService from "./services/ValidationService.js";

...

//inside the component
yourInputChangeHandler(event) {

    if(!ValidationService.firstValidationMethod(event.target.value) {
        //show a validation warning
        return false;
    }
    //proceed
}

어디서든 이 서비스를 이용하세요.검증 규칙이 변경되면 ValidationService.js 파일에만 집중해야 합니다.

다른 서비스에 따라 더 복잡한 서비스가 필요할 수 있습니다.이 경우 서비스 파일에서 정적 개체 대신 클래스 생성자를 반환할 수 있으므로 구성 요소에서 개체의 인스턴스를 직접 생성할 수 있습니다.또한 애플리케이션 전체에서 사용 중인 서비스 오브젝트의 인스턴스가 항상1개만 있는지 확인하기 위해 심플한 싱글톤의 실장을 검토할 수도 있습니다.

첫 번째 답변은 현재의 Container vs Present 패러다임을 반영하지 않습니다.

패스워드의 검증등의 작업을 실시할 필요가 있는 경우는, 그 기능을 사용할 수 있습니다.이 기능을 소품으로 재사용 가능한 뷰에 전달합니다.

컨테이너

따라서 올바른 방법은 Validator Container를 작성하여 그 기능을 속성으로 하여 폼을 랩하고 적절한 소품을 아이에게 전달하는 것입니다.뷰의 경우 검증자 컨테이너가 뷰를 래핑하고 뷰가 컨테이너 로직을 소비합니다.

검증은 컨테이너 속성에서 모두 수행할 수 있지만 타사 검증기 또는 간단한 검증 서비스를 사용하는 경우 서비스를 컨테이너 구성 요소의 속성으로 사용하여 컨테이너 메서드에서 사용할 수 있습니다.안정적 컴포넌트를 위해 이 작업을 수행했는데 매우 잘 작동합니다.

프로바이더

구성이 조금 더 필요한 경우 공급자/소비자 모델을 사용할 수 있습니다.프로바이더는 상위 응용 프로그램 개체(마운트하는 개체)의 근처와 아래에 랩되어 최상위 계층에 구성된 속성의 일부 또는 일부를 컨텍스트 API에 제공하는 고급 구성 요소입니다.그런 다음 콘텍스트를 소비하도록 컨테이너 요소를 설정합니다.

부모/자녀 컨텍스트 관계가 서로 가까울 필요는 없으며, 어떤 식으로든 자식만 후손이 되어야 합니다.리덕스 스토어와 리액트라우터 기능은 다음과 같습니다.나머지 컨테이너에 루트 안정 컨텍스트를 제공하기 위해 사용했습니다(내 컨테이너를 제공하지 않는 경우).

(주의: 콘텍스트 API는 문서에서 실험적인 것으로 표시되어 있지만, 사용하는 것을 고려하면 더 이상 그렇지 않다고 생각합니다).

//An example of a Provider component, takes a preconfigured restful.js
//object and makes it available anywhere in the application
export default class RestfulProvider extends React.Component {
	constructor(props){
		super(props);

		if(!("restful" in props)){
			throw Error("Restful service must be provided");
		}
	}

	getChildContext(){
		return {
			api: this.props.restful
		};
	}

	render() {
		return this.props.children;
	}
}

RestfulProvider.childContextTypes = {
	api: React.PropTypes.object
};

미들웨어

또 다른 방법은 미들웨어를 Redux와 함께 사용하는 것입니다.서비스 개체는 애플리케이션 외부에서 정의하거나 최소한 redux 저장소보다 높게 정의합니다.스토어 작성 중 미들웨어에 서비스를 주입하면 서비스에 영향을 주는 액션이 미들웨어에서 처리됩니다.

이렇게 하면 restful.js 객체를 미들웨어에 삽입하고 컨테이너 메서드를 독립된 액션으로 대체할 수 있습니다.폼 뷰 레이어에 액션을 제공하기 위해서는 컨테이너 컴포넌트가 필요합니다만, connect()와 mapDispatchToProps는 그 점에 대해 설명하고 있습니다.

예를 들어 새로운 v4 react-router-redux는 이 방법을 사용하여 기록 상태에 영향을 줍니다.

//Example middleware from react-router-redux
//History is our service here and actions change it.

import { CALL_HISTORY_METHOD } from './actions'

/**
 * This middleware captures CALL_HISTORY_METHOD actions to redirect to the
 * provided history object. This will prevent these actions from reaching your
 * reducer or any middleware that comes after this one.
 */
export default function routerMiddleware(history) {
  return () => next => action => {
    if (action.type !== CALL_HISTORY_METHOD) {
      return next(action)
    }

    const { payload: { method, args } } = action
    history[method](...args)
  }
}

여러 컴포넌트 간에 공유할 포맷 로직이 필요했고 Angular 개발자 또한 자연스럽게 서비스에 기울었습니다.

나는 논리를 다른 파일에 넣어 공유했다.

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

module.exports = {
    format: format
};

그 후 모듈로 Import했습니다.

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

//then in component

    render() {

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

React의 목적은 논리적으로 결합되어야 하는 것들을 더 잘 결합하는 것입니다.복잡한 "비밀번호 검증" 방법을 설계할 경우 어디에 결합해야 합니까?

사용자가 새 암호를 입력해야 할 때마다 이 암호를 사용해야 합니다.이것은 등록 화면, 패스워드를 잊어버린 화면, 관리자의 패스워드를 다른 사용자에게 리셋하는 화면 등입니다.

그러나 어떤 경우든 텍스트 입력 필드에 항상 연결됩니다.그래서 그게 결합되어야 하는 부분이야.

입력 필드 및 관련 검증 로직으로만 구성된 매우 작은 React 구성 요소를 만듭니다.암호를 입력할 수 있는 모든 양식에 해당 구성 요소를 입력하십시오.

기본적으로 논리용 서비스/공장을 갖는 것과 같은 결과이지만, 직접 입력에 결합하는 것입니다.따라서 이 함수는 영구적으로 연결되어 있기 때문에 검증 입력을 찾을 위치를 해당 함수에 알릴 필요가 없습니다.

같은 상황:여러 개의 Angular 프로젝트를 진행하여 React로 옮긴다는 것은 DI를 통한 간단한 서비스 제공 방법이 없다는 것은 (서비스에 대한 자세한 내용은 차치하고) 부족한 것 같습니다.

컨텍스트와 ES7 데코레이터를 사용하면 다음과 같은 이점을 얻을 수 있습니다.

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

이 사람들은 한 걸음 더 나아간 것 같아요 / 다른 방향으로요

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

여전히 성미에 맞지 않는 일을 하는 것 같아.주요 리액트 프로젝트를 수행한 후 6개월 후에 이 답변을 다시 검토합니다.

편집: 6개월 후 리액트 경험을 더 쌓았습니다.논리의 특성을 고려합니다.

  1. UI에만 연결되어 있습니까?컴포넌트로 이동합니다(승인된 답변).
  2. 주정부 관리와 관련이 있습니까?덩크슛으로 움직여.
  3. 둘 다에 묶여서?개별 파일로 이동하여 셀렉터를 통해 컴포넌트 내에서 소비하고 트렁크 단위로 소비합니다.

일부는 재사용을 위해 HOC에 문의하기도 하지만, 위의 내용은 거의 모든 사용 사례를 대상으로 합니다.또한 문제를 분리하여 UI 중심으로 상태를 유지하기 위해 오리(duck)를 사용하여 상태 관리를 확장하는 것도 고려해 보십시오.

저도 Angular.js 지역에서 왔고 React.js의 서비스와 공장은 더 단순합니다.

나처럼 플레인 함수나 클래스, 콜백 스타일, 이벤트 Mobx를 사용할 수 있습니다.

// Here we have Service class > dont forget that in JS class is Function
class HttpService {
  constructor() {
    this.data = "Hello data from HttpService";
    this.getData = this.getData.bind(this);
  }

  getData() {
    return this.data;
  }
}


// Making Instance of class > it's object now
const http = new HttpService();


// Here is React Class extended By React
class ReactApp extends React.Component {
  state = {
    data: ""
  };

  componentDidMount() {
    const data = http.getData();

    this.setState({
      data: data
    });
  }

  render() {
    return <div>{this.state.data}</div>;
  }
}

ReactDOM.render(<ReactApp />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
  
  <div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

</body>
</html>

다음으로 간단한 예를 제시하겠습니다.

저도 Angular에서 왔습니다.React를 사용해 보겠습니다.현시점에서는 추천(?) 방법 중 하나가 상위 컴포넌트를 사용하는 것 같습니다.

고차 컴포넌트(HOC)는 컴포넌트 로직을 재사용하기 위한 React의 고급 기술입니다.HOC는 그 자체로는 React API의 일부가 아닙니다.그것들은 리액트의 구성적 성격에서 나타나는 패턴이다.

이 있다라고 가정해 보겠습니다.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'));

간단한 데모를 만들었습니다.

편집: 다른 데모에서는 소품을 사용하여 함수 배열을 전달하여 여러 검증 함수 간에 로직을 공유할 수 있습니다.HOC는 다음과 같습니다

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

편집 2: 리액트 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.ins

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"));

주의사항

  • rxj 및 typescript에 따라 다름
  • 서비스에서 화살표 기능을 사용할 수 없습니다.

서비스는 Angular2+에서도 Angular로 제한되지 않습니다.

서비스는 도우미 기능의 집합일 뿐입니다.

또한 애플리케이션을 통해 여러 가지 방법으로 생성 및 재사용할 수 있습니다.

1) 다음과 같이 js 파일에서 내보내는 모든 기능을 분리할 수 있습니다.

export const firstFunction = () => {
   return "firstFunction";
}

export const secondFunction = () => {
   return "secondFunction";
}
//etc

2) 기능집합과 같은 공장법도 사용할 수 있습니다.ES6에서는 함수 생성자가 아닌 클래스일 수 있습니다.

class myService {

  constructor() {
    this._data = null;
  }

  setMyService(data) {
    this._data = data;
  }

  getMyService() {
    return this._data;
  }

}

이 경우 새 키를 사용하여 인스턴스를 만들어야 합니다.

const myServiceInstance = new myService();

또한 이 경우 각 인스턴스는 자체 라이프타임이 있으므로 여러 인스턴스에서 공유할 경우 주의해야 합니다. 이 경우 원하는 인스턴스만 내보내야 합니다.

3) 자신의 기능과 용도가 공유되지 않을 경우, 리액트 컴포넌트에 넣을 수도 있습니다.이 경우 리액트 컴포넌트의 기능과 마찬가지로...

class Greeting extends React.Component {
  getName() {
    return "Alireza Dezfoolian";
  }

  render() {
    return <h1>Hello, {this.getName()}</h1>;
  }
}

4) 다른 방법으로 Redux를 사용할 수도 있고, 임시 스토어이기 때문에 React 어플리케이션에 있다면 사용하는 많은 getter setter 기능에 도움이 될 수 있습니다.마치 대형 스토어처럼 사용자의 상태를 추적하고 컴포넌트 간에 공유할 수 있기 때문에 서비스에 사용하는 getter setter의 많은 번거로움을 없앨 수 있습니다.

항상 DRY 코드를 실행하고 코드를 재사용하고 읽기 쉽게 하기 위해 사용해야 하는 것을 반복하지 않는 것이 좋습니다. 그러나 항목 4에서 언급한 바와 같이 반응 앱의 Angular ways를 따르려고 하지 마십시오. Redux를 사용하면 서비스의 필요성이 줄어들고 항목 1과 같은 재사용 가능한 도우미 기능에 사용할 수 있습니다.

나는 너와 같은 처지에 있다.말씀하신 경우 입력 검증 UI 컴포넌트를 React 컴포넌트로 구현하겠습니다.

검증 로직의 구현 자체가 결합되어서는 안 된다는 데 동의합니다.그래서 나는 그것을 별도의 JS모듈에 넣을 것이다.

즉, 결합되어서는 안 되는 로직의 경우 별도의 파일의 JS 모듈/클래스를 사용하고 require/import를 사용하여 컴포넌트를 "서비스"에서 분리합니다.

이것에 의해, 2개의 의존성 주입과 유닛 테스트를 개별적으로 실시할 수 있습니다.

React 세계에는 두 가지 유형의 논리가 있습니다.스테이트풀 및 스테이트리스이것이 React를 시작할 때 파악해야 할 주요 개념입니다.여기서는 Angular의 돔 직접 업데이트와는 달리 UI를 업데이트해야 하는 상태를 업데이트해야 합니다.로직에는 다음 두 가지 유형이 있습니다.

  1. 이는 상태 변화에 의존하지 않습니다. 즉, 상태 변화에 따라 무언가를 다시 렌더링할 필요가 없는 정적 로직입니다.이러한 경우 일반 js 파일을 생성하여 라이브러리 또는 도우미 메서드처럼 Import합니다.
  2. 상태에 따라 달라지는 코드가 있어 이를 다시 사용해야 하는 경우 Hoc과 새로운 훅의 두 가지 옵션이 있습니다.훅은 이해하기 어렵지만 기본적으로 내부 상태가 변화하면 부모에게 강제로 재렌더(render)를 강제하여 스테이트풀 로직을 정의하고 다른 컴포넌트로 재사용할 수 있습니다.각 훅인스턴스에는 독립된 범위가 있습니다.

스테이트 컴포넌트와 선언 컴포넌트를 이해하지만, 자유롭게 코멘트로 폴로업 질문을 할 수 있도록 하는 것은 조금 사고 전환입니다.

또는 클래스 상속 "http"를 React Component에 주입할 수 있습니다.

소품 오브젝트를 통해.

  1. 업데이트:

    ReactDOM.render(<ReactApp data={app} />, document.getElementById('root'));
    
  2. React Component ReactApp을 다음과 같이 편집하십시오.

    class ReactApp extends React.Component {
    
    state = {
    
        data: ''
    
    }
    
        render(){
    
        return (
            <div>
            {this.props.data.getData()}      
            </div>
    
        )
        }
    }
    

export 키워드를 사용하면 필요한 메서드가 포함된 파일에서 함수를 사용할 수 있습니다.

예를 들어 보겠습니다.은 「 」입니다.someService.ts:

export const foo = (formId: string) => {
    // ... the code is omitted for the brevity
}


export const bar = (): Entity[] => [
    // ... the code is omitted for the brevity
]

export default {
    foo,
    bar,
}

다음으로 이 서비스를 다음과 같은 컴포넌트로 사용할 수 있습니다.

import {
    foo,
    bar,
} from './someService'

const InnerOrderModal: FC = observer(() => {
    const handleFormClick = (value: unknown, item: any) => {
    foo(item.key)
    bar()
    
    return <></>
}

언급URL : https://stackoverflow.com/questions/35855781/having-services-in-react-application

반응형