简体   繁体   English

在助手 function 中调用上下文 function - 反应

[英]Call Context function in helper function - React

Most of my project is built with React class components so I am looking for a solution that won't require me to refactor my class components to functional components.我的大部分项目都是用 React class 组件构建的,所以我正在寻找一种不需要我将 class 组件重构为功能组件的解决方案。 The problem I am having is that I have a file with some helper functions that enable calling an API.我遇到的问题是我有一个包含一些帮助函数的文件,这些函数可以调用 API。 In that helper file, I also want to handle errors.在那个帮助文件中,我还想处理错误。 One of my errors could result in logging the user out.我的错误之一可能导致用户注销。 In my App.js component, I have the following state and functions for logging a user out:在我的App.js组件中,我有以下 state 和用于注销用户的函数:

export const AppContext = React.createContext("app");
class App extends Component {
  constructor() {
    super();
    this.state = {
      loggedInStatus: "NOT_INITIALIZED",
      user: {},
    };
  }

 handleLogout = () => {
    request.delete("/logout").then(response => {
      this.setState({
        loggedInStatus: "NOT_LOGGED_IN",
        user: {},
      });
     }).catch(error => {
       console.log("error", error);
     });
  };

  render() {
    return(
        <AppContext.Provider
          value={{
              state: this.state,
              handleLogout: this.handleLogout
          }}
        >
          <BrowserRouter>
             {code that renders certain pages}
          </BrowserRouter>
        </AppContext.Provider>
    )
  }
}

I've also created this HOC:我还创建了这个 HOC:

import React from 'react';
import {AppContext} from '../App.js'

export function withAppContext(Component) {
    return function WrapperComponent(props) {
        return (
            <AppContext.Consumer>
                {state => <Component {...props} context={state} />}
            </AppContext.Consumer>
        );
    };
}

I can import and use this context in any of my class components and call the handleLogout function that is provided via the context.我可以在我的任何 class 组件中导入和使用此上下文,并调用通过上下文提供的handleLogout function。 However, I have this helper file and I want to access the handleLogout function in the helper file rather than some child component.但是,我有这个帮助文件,我想访问帮助文件中的handleLogout function 而不是一些子组件。 Here is my helper file:这是我的帮助文件:

import axios from 'axios';

const request = (function(){
  function url(){
    return window.$url;
  }

  return {
    get: function(uri, params={}){
      return axios.get(url() + uri,  {withCredentials: true, params: params})
    },
    post: function(uri, data){
      return axios.post(url() + uri, data, {withCredentials: true})
    },
    patch: function(uri, data){
      return axios.patch(url() + uri, data, {withCredentials: true})
    },
    delete: function(uri){
      return axios.delete(url() + uri, {withCredentials: true})
    },
    handleError: function(error){
      //I want to call the handleLogout function here
    }

  }
})();

export default request;

I currently call these other helper functions from within a class component like so:我目前从 class 组件中调用这些其他辅助函数,如下所示:

import request from "./RequestHelper";


class CustomerForm extends Component{

  constructor(props){
    super(props);
    this.state = {
      isSubmitting: false
    }
  }
    
  handleSubmit = () => {
       request.get("/someurl").catch((err) => {
           //I call request.handleError(err) here
           //which will log the user out depending on the error. 
       });
  }
}

Instead of creating a self-invoked request , expose out the ability to pass a React context (or any other config object, etc) to it.与其创建自调用request ,不如公开向其传递 React 上下文(或任何其他配置 object 等)的能力。

For example:例如:

const request = (context = {}) => {
  function url() {
    return window.$url;
  }

  return {
    get: function (uri, params = {}) {
      return axios.get(url() + uri, { withCredentials: true, params: params });
    },
    post: function (uri, data) {
      return axios.post(url() + uri, data, { withCredentials: true });
    },
    patch: function (uri, data) {
      return axios.patch(url() + uri, data, { withCredentials: true });
    },
    delete: function (uri) {
      return axios.delete(url() + uri, { withCredentials: true });
    },
    handleError: function (error) {
      // Access the enclosed context
      if (error === 404) context.logout();
    }
  };
};

Usage用法

import { context } from './path/to/context';

...

const requestWithContext = request(context);

requestWithContext
  .get("/somePath")
  .catch(requestWithContext.handleError);

编辑 call-context-function-in-helper-function-react

I will advise that this appears to unnecessarily couple your axios request utility to your UI/context, in a sub-optimal way.我会建议这似乎不必要地将您的 axios 请求实用程序以次优方式耦合到您的 UI/上下文。 It may be easier/cleaner to incorporate request into your context provider instead, and simply handle the axios failures directly in the .catch block of the Promise chain.request合并到您的上下文提供程序中可能更容易/更清洁,并且只需在 Promise 链的.catch块中直接处理 axios 故障。

Context is meant to pass props from one component to another.上下文旨在将道具从一个组件传递到另一个组件。 Since in your case you have handleLogout tied to your component, you can't use it outside of components tree.由于在您的情况下您已将handleLogout绑定到您的组件,因此您不能在组件树之外使用它。

If you want to use it everywhere in your code and not only in react, you can create some service that you can subscribe to in components, so when you logging out, your components would be notified about it.如果您想在代码中的任何地方使用它,而不仅仅是在 react 中,您可以创建一些可以在组件中订阅的服务,因此当您注销时,您的组件会收到通知。 The most plain and simple implementation would be this:最简单明了的实现是这样的:

class LogoutService {
  // you maintain list of subscribers
  subscrribers = new Set();
  // Any part of code can subscribe with callback to do necessary stuff
  subscribe(fn) {
    this.subscribers.add(fn);
    // wheen component unmounts, it should unsubscribe
    return function unsubscribe() {
      this.subscribers.delete(fn);
    };
  }
  // your main function that do stuff and then triggers all subscribers
  logout() {
    return new Promise((resolve) => {
      resolve();
    }).then(() => this.subscribers.forEach((fn) => fn()));
  }
}

// you export this instance which can be imported wherever in your application as a singleton
let logoutService = new LogoutService();

Your compoents now can subscribe to such service and will be notified if logout event occured.您的组件现在可以订阅此类服务,并在发生注销事件时收到通知。 And your non components can trigger logout anywhere.而且您的非组件可以在任何地方触发注销。

Here is an example where I trigger logout from one react app and it notifies another这是一个示例,我从一个反应应用程序触发注销并通知另一个

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

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