React Native 在不同导出函数中的 helper api 文件中使用上下文 [英] React Native use Context in helper api file from within different exported functions

查看:91
本文介绍了React Native 在不同导出函数中的 helper api 文件中使用上下文的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有一些导出函数的帮助文件.我有一个带有一些共享数据的 ContextProvider.现在我需要从辅助函数内部更改上下文中的数据.

I have a helper file with some exported functions. And I have a ContextProvider with some shared data. Now I need to change the Data in the Context from inside the helper functions.

但是如果我在函数体内部调用 useContext 语句并且在外部执行它,则会出现错误.

But there are errors if I call the useContext statement inside the function bodys and also if I do it outside.

如果我在帮助文件中创建一个默认函数 MyHelper(),我可以调用内部的 useContext 及其工作.但是我不能使用不同的函数作为来自另一个文件的 api.只有 MyHelper().

If I create one default function MyHelper() in the helper file I can call the useContext inside and its working. But then I can't use different functions as api from another file. Only the MyHelper().

如何在另一个 .js 文件中调用多个导出函数并更改上下文数据?

How can I call more than one exported functions in another .js File and also change there context data?

我制作了一个示例代码,它在没有原始代码开销的情况下显示了我的问题:

I have made an example code which shows my problem without the overhead of my original code:

MyScreen.js

MyScreen.js

import React, {useContext} from 'react';
import {View, Button} from 'react-native';

import {MyContext} from '../MyProvider'; // assume this exists and is working
import {myChangeNameFunction} from '../helpers/MyHelper';

const MyScreen = () => { 
  const {name, setName} = useContext(MyContext); // does work here
  
  return (
    <View>
      <Button
        title={name} //just as easy example
        onPress={() => myChangeNameFunction('test')}
      />
   </View>
      
  );
}

export default MyScreen;

MyHelper.js

MyHelper.js

import React, {useContext} from 'react';
import {MyContext} from '../MyProvider';
    
    //const {name, setName} = useContext(MyContext); // does not work
    
    export const myChangeNameFunction = (test) => { 
        //const {name, setName} = useContext(MyContext); // does not work
        setName(test);
    }
    
    export const anotherFunction = (test) => { 
        //const {name, setName} = useContext(MyContext); // does not work
        setName(test);
    }

更新:

也许是一个更好的例子:

Maybe a better example:

MyScreen.js

MyScreen.js

import React, {useContext} from 'react';
import {View, Text, Button} from 'react-native';
import GeocoderOsm from 'react-native-geocoder-osm';
import {MyContext} from '../MyProvider';
//import {getGPSbyAddress} from '../helpers/MyHelper'; 
// I want to exclude functions below and instead import them from helper file 

const MyScreen = () => { 
  const {address, setAddress} = useContext(MyContext);
  
  // imagine here are a lot of functions like these below.
  // I want to exclude them from this file to a MyHelper.js
  // So the MyScreen.js File is not so big and with chaos.
  // Also I could import and reuse these functions from other Screens than MyScreen.js.
  
  const getGPSbyAddress = (place) => { 
      GeocoderOsm.getGeoAddress(place).then((res) => {
      // setAddress is working here. But if I outsource the function to MyHelper.js File 
      // I can't access the setAddress in the Context. And I also can't return 
      // the res output because its kind of async - because of the then() function 
      // of the OSM lib. So I just want to save it to context if its finished.
        setAddress(res);    
      }).catch((e) => { 
        console.log('error', e)
      });
  }
  
  return (
    <View>
      <Button
        title='Get GPS'
        onPress={() => getGPSbyAddress('London') }
      />
      <Text>{address}</Text>
   </View>
      
  );
}

export default MyScreen;

MyHelper.js

MyHelper.js

import React, {useContext} from 'react';
import GeocoderOsm from 'react-native-geocoder-osm';
import {MyContext} from '../MyProvider';
    
  //const {address, setAddress} = useContext(MyContext); // does not work here
    
  export const getGPSbyAddress = (place) => { 
      //const {address, setAddress} = useContext(MyContext); // does not work here
      
      GeocoderOsm.getGeoAddress(place).then((res) => {
        setAddress(res);    // this is not working here because I cant call useContext anywhere.
      }).catch((e) => { 
        console.log('error', e)
      });
  }
  
  export const getAddressByGPS = (lat, lon) => { 
      //const {address, setAddress} = useContext(MyContext); // does not work here
      
      GeocoderOsm.getGeoCodePosition(lat, lon).then((res) => {
        setAddress(res);    // this is not working here because I cant call useContext anywhere.
      }).catch((e) => { 
        console.log('error', e)
      });
  }
  
  // ... a lot of more functions

因此,如果没有解决方案可以从 MyHelper.js 文件中的函数设置上下文...然后我如何将某些函数外包到一个单独的文件中(以便更好地阅读和重用)并获得我的 {address}使用从可能异步获取地址的外包函数中获取的数据呈现.感谢您的耐心等待.

So if there is no solution to set the Context from the functions in the MyHelper.js File... How can i then outsource some functions in an seperate file (for better reading and reuse) and also get my {address} rendered with the fetched data from the outsourced function which probably fetched the address asyncly. Thanks for your patience.

推荐答案

您看到错误的原因是您在组件主体之外调用了一个钩子.在您的情况下,这是 useContext 钩子.在第一种情况下,您在模块级别调用它,在其他两种情况下,您在函数内部调用它,然后在处理程序中调用该函数,该处理程序也是外部"处理程序.组件的.您需要做的是提取您在组件中无条件调用的钩子.该钩子可以公开(返回)一个可以在处理程序中调用的函数.

The reason you see the error is that you are calling a hook outside of the component body. In your case that is the useContext hook. In the first case you are calling it on a module level and in the other two cases you call it inside of a function but then you call that function in a handler which is also "outside" of the component. What you need to do is to extract a hook that you call unconditionally in your component. That hook can expose (return) a function that you can call in your handler.

您可以创建自己的自定义钩子,这些钩子由其他钩子组成:

You can create your own custom hooks which are composed from other hooks:

MyHelper.js

MyHelper.js

import {MyContext} from '../MyProvider';

export const useName = () => {
    return useContext(MyContext);
}

然后您可以在组件中使用它.请注意,自定义钩子必须返回组件需要使用的所有内容.

You can then use it in a component. Note that the custom hook has to return everything that the component needs to use.

MyScreen.js

MyScreen.js

import {useName} from '../helpers/MyHelper';

const MyScreen = () => { 
  const {name, setName} = useName();
  
  return (
    <View>
      <Button
        title={name}
        onPress={() => setName('test')}
      />
   </View>
      
  );
}

在这种情况下,useName 钩子将隐式使用 MyContext 而不必显式传递它.它当然可以包含更多钩子,并根据使用它的组件的需要返回相关值.

In this case the useName hook will implicitly use MyContext without explicitly having to pass it. It could of course contain many more hooks and return the relevant values as needed by components using it.

编辑

给定更详细的示例,您将在 MyHelper.js 文件中创建一个自定义挂钩,该挂钩返回所有需要的函数.它不能有任何不同,因为这些功能首先需要上下文.它们是您上下文中数据的闭包.因此,当您的助手需要首先获取上下文时,它需要调用 useContext 使其成为一个钩子.

Given your more detailed example you would create a custom hook in your MyHelper.js file, which returns all those functions needed. It can't work any different as those functions need the context in the first place. They are closures over data from your context. So as your helper needs to first get the context it needs to call useContext which makes it a hook.

MyHelper.js

MyHelper.js

import {MyContext} from '../MyProvider';

export const useUserData = () => {
    const {
        name, setName,
        address, setAddress
    } = useContext(MyContext);

    const myChangeNameFunction = test => setName(test);

    const getGPSbyAddress = (place) => { 
        GeocoderOsm.getGeoAddress(place).then((res) => {
            setAddress(res);    
        }).catch((e) => { 
            console.log('error', e)
        });
     }

     const getAddressByGPS = (lat, lon) => {   
         GeocoderOsm.getGeoCodePosition(lat, lon).then((res) => {
             setAddress(res);   
         }).catch((e) => { 
             console.log('error', e)
         });
     }

     // return your data and updater functions 
     // so you can access them in your component
     return {
         name, address, 
         getGPSbyAddress, getAddressByGPS, myChangeNameFunction
     };
}

您可以像这样使用自定义钩子:

You can use your custom hook like that:

MyScreen.js

MyScreen.js

import {useUserData} from '../helpers/MyHelper';

const MyScreen = () => { 
    const {
        name, address, 
        getGPSbyAddress, myChangeNameFunction
    } = useUserData();

    return (
        <View>
            <Button
                title='Get GPS'
                onPress={() => getGPSbyAddress('London') }
            />
            <Text>{address}</Text>
            <Button
                title={name}
                onPress={() => myChangeNameFunction('test')}
            />
        </View>
    );
}

您当然可以同时在多个不同的组件中使用该钩子.您还可以将这个自定义钩子拆分为多个仅具有相关功能的钩子.

You can of course use that hook in multiple different components simultanously. You can also split this custom hook into multiple hooks that only have certain functions that are related.

这篇关于React Native 在不同导出函数中的 helper api 文件中使用上下文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆