【问题标题】:useDispatch() Error: Could not find react-redux context value; please ensure the component is wrapped in a <Provider>useDispatch() 错误:找不到 react-redux 上下文值;请确保组件包装在 <Provider>
【发布时间】:2020-06-05 08:07:35
【问题描述】:

我正在尝试使用 React-Redux 库,但我收到标题错误。我用 Provider 包装了我的组件,但我仍然得到错误,只有当我实现 useDispatch() 钩子时。

应用程序运行良好,直到我添加了 useDispatch() 行。可以删除有关调度功能的其余行,但我仍然得到相同的错误。

如果您能帮助我,我将不胜感激。谢谢

这是我的代码:

import 'react-native-gesture-handler';
import {NavigationContainer} from '@react-navigation/native';
import Navigator from './navigation/Navigator';

import React, {useEffect, useState, useCallback} from 'react';
import {SafeAreaView, StyleSheet, Text, View} from 'react-native';

import {createStore, combineReducers} from 'redux';
import {Provider, useDispatch} from 'react-redux';
import dataReducer from './store/reducers/dataReducer';
import {CONSTANTS} from './constants/constants';
import {saveInitialData} from './store/actions/dataActions';

const App = () => {
  const [fetched, setFetched] = useState(initialState);

  const dispatch = useDispatch();

  const saveInitialDataHandler = useCallback(data => {
    dispatch(saveInitialData(data));
    callback;
  }, []);

  const rootReducer = combineReducers({
    content: dataReducer,
  });

  const store = createStore(rootReducer);

  useEffect(() => {
    fetchData();
  }, []);

  const fetchData = () => {
    fetch(CONSTANTS.database)
      .then(response => response.json())
      .then(responseJSON => {
        setFetched(true);
        saveInitialDataHandler(responseJSON);
      });
  };

  if (!fetched) {
    return (
      <Provider store={store}>
        <View stlye={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
          <Text></Text>
        </View>
      </Provider>
    );
  } else {
    return (
      <Provider store={store}>
        <NavigationContainer>
          <SafeAreaView style={styles.SafeAreaView}>
            <Navigator></Navigator>
          </SafeAreaView>
        </NavigationContainer>
      </Provider>
    );
  }
};

const styles = StyleSheet.create({
  SafeAreaView: {flex: 1},
});

export default App;

【问题讨论】:

    标签: reactjs react-native redux react-redux


    【解决方案1】:

    App 必须包含在 provider 中,因为您在其中使用了 useDispatch。现在还只是个孩子。 Provider 设置上下文,因此只有其子级才能访问它,而不是父级。

    一种解决方案是为其创建一个包装器组件:

    const AppWrapper = () => {
      const store = createStore(rootReducer);
    
      return (
        <Provider store={store}> // Set context
          <App /> // Now App has access to context
        </Provider>
      )
    }
    
    const App = () => {
      const dispatch = useDispatch(); // Works!
    ...
    

    【讨论】:

    • 谢谢,它成功了。对于任何使用它的人,还记得导出您的 AppWrapper,而不是您的 App!
    • 基本上确保使用 Provider 而不是 index.js 文件来包装您的 App 组件,该文件将 App 组件安装到 DOM。
    • 您好,我遇到了同样的问题,当我尝试这种方法时,我收到“ReferenceError:找不到变量:rootReducer”
    • rootReducer 是 OP 给他们的组合减速器的名称,您的名称可能会有所不同,具体取决于您如何设置减速器并导入它们。
    【解决方案2】:

    也许您将 Provider 导入到 App.js 文件中。 Provider需要导入到文件index.js中。

    /*index.js*/
    import React from 'react';
    import ReactDOM from 'react-dom';
    import { Provider } from 'react-redux';
    import { store } from './store/reduxStore';
    import './index.css';
    import App from './App';
    import reportWebVitals from './reportWebVitals';
    
        ReactDOM.render(
      <React.StrictMode>
        <Provider store={store}>
          <App />
        </Provider>
      </React.StrictMode>,
      document.getElementById('root')
    );
    

    【讨论】:

      【解决方案3】:

      如果您在运行npm run test 时遇到此错误,则问题与您的测试文件有关。

      通过以下代码更新或替换您的app.test.tsx

      注意:如果您还没有安装redux-mock-store,请不要忘记安装。

      import React from 'react';
      import { render } from '@testing-library/react';
      
      import App from './App';
      
      import { Provider } from 'react-redux';
      import configureStore from 'redux-mock-store';
      
      describe('With React Testing Library', () => {
          const initialState = { output: 10 };
          const mockStore = configureStore();
          let store;
      
          it('Shows "Hello world!"', () => {
              store = mockStore(initialState);
              const { getByText } = render(
                  <Provider store={store}>
                      <App />
                  </Provider>
              );
      
              expect(getByText('Hello World!')).not.toBeNull();
          });
      });
      

      我在搜索 1 小时后得到了这个解决方案。 非常感谢OSTE

      原解决方案:Github issues/8145 and solution link


      使用此解决方案,如果您遇到 TypeError: window.matchMedia is not a function 之类的错误,请通过此方式解决。将这些行添加到您的 setupTests.ts 文件中。原解决方案链接stackoverflow.com/a/64872224/5404861

      global.matchMedia = global.matchMedia || function () {
        return {
          addListener: jest.fn(),
          removeListener: jest.fn(),
        };
      };
      

      【讨论】:

        【解决方案4】:

        我对 react-native 应用程序的同一个 index.js 文件执行了此操作。 这样,您就不必导出和添加另一个文件,只是为了用提供​​者包装应用程序。

        const ReduxProvider = () => {
            return(
                <Provider store={store}>
                    <App />
                </Provider>
            )
        }
        
        AppRegistry.registerComponent(appName, () => ReduxProvider);
        

        【讨论】:

          【解决方案5】:

          发生在我身上,当我将 React 组件作为函数调用时,没有将其用作虚拟 dom,Comp 被独立调用,而不是呈现为某个元素的子元素

          function Comp() {
            const a = useSelector(selectA); // throws error
          }
          Comp();
          

          所以在我的情况下,解决方案是调用 Comp 和一个组件,而不是作为一个函数 即&lt;Comp /&gt;

          【讨论】:

          • 所以。解决方案是什么?
          • 解决方案是使用一级间接 - 即在 Comp 中调用选择器。这也是公认的解决方案。
          猜你喜欢
          • 2020-09-08
          • 1970-01-01
          • 2023-02-24
          • 1970-01-01
          • 2021-05-15
          • 1970-01-01
          • 2020-05-31
          • 2022-06-24
          • 2021-03-12
          相关资源
          最近更新 更多