การละเมิดที่ไม่คงที่: ไม่พบ“ ร้านค้า” ในบริบทหรืออุปกรณ์ประกอบฉากของ“ เชื่อมต่อ (SportsDatabase)”


142

รหัสเต็มได้ที่นี่: https://gist.github.com/js08/0ec3d70dfda76d7e9fb4

สวัสดี

  • ฉันมีแอปพลิเคชั่นที่จะแสดงเทมเพลตที่แตกต่างกันสำหรับเดสก์ท็อปและมือถือตามสภาพแวดล้อมการสร้าง
  • ฉันสามารถพัฒนามันได้โดยที่ฉันต้องการซ่อนเมนูนำทางสำหรับเทมเพลตมือถือของฉัน
  • ตอนนี้ฉันสามารถเขียนกรณีทดสอบหนึ่งกรณีซึ่งดึงค่าทั้งหมดผ่าน proptypes และแสดงอย่างถูกต้อง
  • แต่ไม่แน่ใจว่าจะเขียนกรณีทดสอบหน่วยได้อย่างไรเมื่ออุปกรณ์เคลื่อนที่ไม่ควรแสดงองค์ประกอบการนำทาง
  • ฉันพยายาม แต่ฉันพบข้อผิดพลาด ... คุณสามารถบอกฉันได้ว่าจะแก้ไขได้อย่างไร
  • รหัสด้านล่าง

กรณีทดสอบ

import {expect} from 'chai';
import React from 'react';
import TestUtils from 'react-addons-test-utils';
import {SportsTopPortion} from '../../../src/components/sports-top-portion/sports-top-portion.jsx';
require('../../test-utils/dom');


describe('"sports-top-portion" Unit Tests', function() {
    let shallowRenderer = TestUtils.createRenderer();

    let sportsContentContainerLayout ='mobile';
    let sportsContentContainerProfile = {'exists': 'hasSidebar'};
    let sportsContentContainerAuthExchange = {hasValidAccessToken: true};
    let sportsContentContainerHasValidAccessToken ='test'; 

    it('should render correctly', () => {
        shallowRenderer.render(<SportsTopPortion sportsWholeFramework={sportsContentContainerLayout} sportsPlayers={sportsContentContainerProfile} sportsAuthentication={sportsContentContainerAuthExchange} sportsUpperBar={{activeSportsLink:'test'}} />);
        //shallowRenderer.render(<SportsTopPortion sportsWholeFramework={sportsContentContainerLayout} sportsPlayers={sportsContentContainerProfile} hasValidAccessToken={sportsContentContainerHasValidAccessToken}  />);

        let renderedElement = shallowRenderer.getRenderOutput();
        console.log("renderedElement------->" + JSON.stringify(renderedElement));

        expect(renderedElement).to.exist;
    });

    it('should not render sportsNavigationComponent when sports.build is mobile', () => {
        let sportsNavigationComponent = TestUtils.renderIntoDocument(<SportsTopPortion sportsWholeFramework={sportsContentContainerLayout} sportsPlayers={sportsContentContainerProfile} sportsAuthentication={sportsContentContainerAuthExchange} sportsUpperBar={{activeSportsLink:'test'}} />);
        console.log("sportsNavigationComponent------->" + JSON.stringify(sportsNavigationComponent));

        //let footnoteContainer = TestUtils.findRenderedDOMComponentWithClass(sportsNavigationComponent, 'linkPack--standard');

        //expect(footnoteContainer).to.exist;
    });

});

ข้อมูลโค้ดที่จะต้องเขียนกรณีทดสอบ

if (sports.build === 'mobile') {
    sportsNavigationComponent = <div />;
    sportsSideMEnu = <div />;
    searchComponent = <div />;
    sportsPlayersWidget = <div />;
}

ความผิดพลาด

1) "sports-top-portion" Unit Tests should not render sportsNavigationComponent when sports.build is mobile:
     Invariant Violation: Could not find "store" in either the context or props of "Connect(SportsDatabase)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(SportsDatabase)".
      at Object.invariant [as default] (C:\sports-whole-page\node_modules\invariant\invariant.js:42:15)
      at new Connect (C:\sports-whole-page\node_modules\react-redux\lib\components\createConnect.js:135:33)
      at [object Object].ReactCompositeComponentMixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactCompositeComponent.js:148:18)
      at [object Object].wrapper [as mountComponent] (C:\sports-whole-page\node_modules\react\lib\ReactPerf.js:66:21)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (C:\sports-whole-page\node_modules\react\lib\ReactMultiChild.js:241:44)
      at ReactDOMComponent.Mixin._createContentMarkup (C:\sports-whole-page\node_modules\react\lib\ReactDOMComponent.js:591:32)
      at ReactDOMComponent.Mixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactDOMComponent.js:479:29)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (C:\sports-whole-page\node_modules\react\lib\ReactMultiChild.js:241:44)
      at ReactDOMComponent.Mixin._createContentMarkup (C:\sports-whole-page\node_modules\react\lib\ReactDOMComponent.js:591:32)
      at ReactDOMComponent.Mixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactDOMComponent.js:479:29)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at [object Object].ReactCompositeComponentMixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactCompositeComponent.js:225:34)
      at [object Object].wrapper [as mountComponent] (C:\sports-whole-page\node_modules\react\lib\ReactPerf.js:66:21)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (C:\sports-whole-page\node_modules\react\lib\ReactMultiChild.js:241:44)
      at ReactDOMComponent.Mixin._createContentMarkup (C:\sports-whole-page\node_modules\react\lib\ReactDOMComponent.js:591:32)
      at ReactDOMComponent.Mixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactDOMComponent.js:479:29)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at [object Object].ReactCompositeComponentMixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactCompositeComponent.js:225:34)
      at [object Object].wrapper [as mountComponent] (C:\sports-whole-page\node_modules\react\lib\ReactPerf.js:66:21)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at ReactDOMComponent.ReactMultiChild.Mixin.mountChildren (C:\sports-whole-page\node_modules\react\lib\ReactMultiChild.js:241:44)
      at ReactDOMComponent.Mixin._createContentMarkup (C:\sports-whole-page\node_modules\react\lib\ReactDOMComponent.js:591:32)
      at ReactDOMComponent.Mixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactDOMComponent.js:479:29)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at [object Object].ReactCompositeComponentMixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactCompositeComponent.js:225:34)
      at [object Object].wrapper [as mountComponent] (C:\sports-whole-page\node_modules\react\lib\ReactPerf.js:66:21)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at [object Object].ReactCompositeComponentMixin.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactCompositeComponent.js:225:34)
      at [object Object].wrapper [as mountComponent] (C:\sports-whole-page\node_modules\react\lib\ReactPerf.js:66:21)
      at Object.ReactReconciler.mountComponent (C:\sports-whole-page\node_modules\react\lib\ReactReconciler.js:37:35)
      at mountComponentIntoNode (C:\sports-whole-page\node_modules\react\lib\ReactMount.js:266:32)
      at ReactReconcileTransaction.Mixin.perform (C:\sports-whole-page\node_modules\react\lib\Transaction.js:136:20)
      at batchedMountComponentIntoNode (C:\sports-whole-page\node_modules\react\lib\ReactMount.js:282:15)
      at ReactDefaultBatchingStrategyTransaction.Mixin.perform (C:\sports-whole-page\node_modules\react\lib\Transaction.js:136:20)
      at Object.ReactDefaultBatchingStrategy.batchedUpdates (C:\sports-whole-page\node_modules\react\lib\ReactDefaultBatchingStrategy.js:62:19)
      at Object.batchedUpdates (C:\sports-whole-page\node_modules\react\lib\ReactUpdates.js:94:20)
      at Object.ReactMount._renderNewRootComponent (C:\sports-whole-page\node_modules\react\lib\ReactMount.js:476:18)
      at Object.wrapper [as _renderNewRootComponent] (C:\sports-whole-page\node_modules\react\lib\ReactPerf.js:66:21)
      at Object.ReactMount._renderSubtreeIntoContainer (C:\sports-whole-page\node_modules\react\lib\ReactMount.js:550:32)
      at Object.ReactMount.render (C:\sports-whole-page\node_modules\react\lib\ReactMount.js:570:23)
      at Object.wrapper [as render] (C:\sports-whole-page\node_modules\react\lib\ReactPerf.js:66:21)
      at Object.ReactTestUtils.renderIntoDocument (C:\sports-whole-page\node_modules\react\lib\ReactTestUtils.js:76:21)
      at Context.<anonymous> (C:/codebase/sports-whole-page/test/components/sports-top-portion/sports-top-portion-unit-tests.js:28:41)
      at callFn (C:\sports-whole-page\node_modules\mocha\lib\runnable.js:286:21)
      at Test.Runnable.run (C:\sports-whole-page\node_modules\mocha\lib\runnable.js:279:7)
      at Runner.runTest (C:\sports-whole-page\node_modules\mocha\lib\runner.js:421:10)
      at C:\sports-whole-page\node_modules\mocha\lib\runner.js:528:12
      at next (C:\sports-whole-page\node_modules\mocha\lib\runner.js:341:14)
      at C:\sports-whole-page\node_modules\mocha\lib\runner.js:351:7
      at next (C:\sports-whole-page\node_modules\mocha\lib\runner.js:283:14)
      at Immediate._onImmediate (C:\sports-whole-page\node_modules\mocha\lib\runner.js:319:5)

คำตอบ:


182

มันค่อนข้างง่าย connect()(MyPlainComponent)คุณกำลังพยายามที่จะทดสอบส่วนประกอบเสื้อคลุมที่สร้างขึ้นโดยการโทร คอมโพเนนต์ wrapper นั้นคาดว่าจะสามารถเข้าถึงที่จัดเก็บ Redux ปกติร้านค้าที่สามารถใช้ได้เป็นเพราะที่ด้านบนของลำดับชั้นคอมโพเนนท์ที่คุณต้องการมีcontext.store <Provider store={myStore} />อย่างไรก็ตามคุณแสดงองค์ประกอบที่เชื่อมต่อด้วยตัวเองโดยไม่มีร้านค้าดังนั้นจึงเกิดข้อผิดพลาด

คุณมีตัวเลือกน้อย:

  • สร้างร้านค้าและแสดง<Provider>ส่วนประกอบที่เชื่อมต่อของคุณ
  • สร้างร้านค้าและส่งโดยตรงเป็นใน<MyConnectedComponent store={store} />ขณะที่องค์ประกอบที่เชื่อมต่อจะยอมรับ "ร้านค้า" เป็นเสา
  • อย่ารบกวนการทดสอบส่วนประกอบที่เชื่อมต่อ ส่งออกรุ่น "ธรรมดา" ที่ไม่ได้เชื่อมต่อและทดสอบแทน หากคุณทดสอบส่วนประกอบธรรมดาและmapStateToPropsฟังก์ชั่นของคุณคุณสามารถถือว่ารุ่นที่เชื่อมต่อนั้นทำงานได้อย่างปลอดภัย

คุณอาจต้องการที่จะอ่านผ่าน "ทดสอบ" หน้าเอกสาร Redux: https://redux.js.org/recipes/writing-tests

แก้ไข :

หลังจากที่เห็นจริงว่าคุณโพสต์แหล่งที่มาและอ่านข้อผิดพลาดอีกครั้งปัญหาที่แท้จริงไม่ได้อยู่ในองค์ประกอบ SportsTopPane ปัญหาคือคุณกำลังพยายามเรนเดอร์ SportsTopPane ซึ่ง "สมบูรณ์" ซึ่งทำให้ลูก ๆ ของมันทุกคนแทนที่จะทำตัว "ตื้น" เหมือนที่คุณเป็นในกรณีแรก บรรทัดsearchComponent = <SportsDatabase sportsWholeFramework="desktop" />;กำลังแสดงองค์ประกอบที่ฉันถือว่าเชื่อมต่อด้วยดังนั้นจึงคาดว่าร้านค้าจะพร้อมใช้งานในคุณลักษณะ "บริบท" ของ React

ณ จุดนี้คุณมีสองตัวเลือกใหม่:

  • ทำเฉพาะการเรนเดอร์ "ตื้น" ของ SportsTopPane เพื่อที่คุณจะไม่บังคับให้แสดงภาพลูกอย่างเต็มที่
  • หากคุณต้องการแสดงผลแบบ "ลึก" ของ SportsTopPane คุณจะต้องจัดเก็บ Redux ไว้ในบริบท ฉันขอแนะนำให้คุณดูที่ห้องสมุดทดสอบเอนไซม์ซึ่งช่วยให้คุณทำอย่างนั้น ดูhttp://airbnb.io/enzyme/docs/api/ReactWrapper/setContext.htmlเพื่อดูตัวอย่าง

โดยรวมแล้วฉันจะทราบว่าคุณอาจพยายามทำสิ่งนี้มากเกินไปในองค์ประกอบหนึ่งและอาจต้องการพิจารณาแยกเป็นชิ้นเล็ก ๆ โดยใช้ตรรกะน้อยลงต่อองค์ประกอบ


ฉันพยายาม แต่ไม่แน่ใจว่าจะทำอย่างไร ... คุณสามารถอัปเดตในกรณีทดสอบของฉันได้ไหม

1
ฉันสมมติว่าใน SportsTopPortion.js let SportsTopPortion = connect(mapStateToProps)(SomeOtherComponent)คุณมี คำตอบที่ง่ายที่สุดคือการทดสอบที่อื่น ๆconnectองค์ประกอบไม่ใช่องค์ประกอบที่ส่งกลับโดย
markerikson

1
เอเอชเอ ตอนนี้ฉันเห็นสิ่งที่เกิดขึ้น ปัญหาไม่ได้อยู่ที่ SportsTopPane นั้นเอง ปัญหาคือคุณกำลังสร้างเรนเดอร์ "เต็ม" ของ SportsTopPane ไม่ใช่เรนเดอร์ที่ "ตื้น" ดังนั้น React จึงพยายามทำให้เด็ก ๆ searchComponent = <SportsDatabase sportsWholeFramework="desktop" />;เกิดข้อผิดพลาดหมายถึงบรรทัด นั่นคือองค์ประกอบที่เชื่อมต่อที่คาดว่าจะมีร้านค้าและทำลาย ดังนั้นสองข้อเสนอแนะใหม่: ทำเฉพาะการเรนเดอร์ตื้น ๆ ของ SportsTopPane หรือใช้ไลบรารีเช่น Enzyme เพื่อทดสอบ ดูairbnb.io/enzyme/docs/api/ReactWrapper/setContext.html
markerikson

คุณสามารถบอกฉันได้ว่าจะเขียนกรณีทดสอบสำหรับสถานการณ์นี้ได้อย่างไร แต่ไม่แน่ใจว่าจะเขียนกรณีทดสอบหน่วยได้อย่างไรเมื่ออุปกรณ์พกพาไม่ควรแสดงส่วนประกอบ nav `` `

3
การตอบคนที่ติดอยู่หรืองงงวยกับวลีที่ว่า "มันค่อนข้างง่าย" สามารถหลุดพ้นจากการดูหมิ่นหรือรุนแรง โปรดใช้เท่าที่จำเป็น
jayqui

97

วิธีแก้ปัญหาที่เป็นไปได้ที่เหมาะกับฉันด้วยความตลกขบขัน

import React from "react";
import { shallow } from "enzyme";
import { Provider } from "react-redux";
import configureMockStore from "redux-mock-store";
import TestPage from "../TestPage";

const mockStore = configureMockStore();
const store = mockStore({});

describe("Testpage Component", () => {
    it("should render without throwing an error", () => {
        expect(
            shallow(
                <Provider store={store}>
                    <TestPage />
                </Provider>
            ).exists(<h1>Test page</h1>)
        ).toBe(true);
    });
});

1
ทำงานได้ดีแทนที่จะต้องผ่านอุปกรณ์ประกอบฉากทีละตัว
ghostkraviz

2
ขอบคุณทางออกที่ดีมาก ฉันมีปัญหานี้เพราะฉันใช้ส่วนประกอบแอพระดับบนสุดที่มีการกำหนดเส้นทางและมีการจัดเก็บแอพลูกในแต่ละเส้นทางดังนั้นฉันจึงไม่จำเป็นต้องส่งอุปกรณ์ประกอบฉากเข้าไปในเราเตอร์ ฉันเปลี่ยนมันเล็กน้อยสำหรับการใช้งานของฉัน const wrapper = ตื้น (<store store = {store}> <App /> </Provider>); คาดหวัง (wrapper.contain (<App />)).toBe(true);
สมองเล็ก ๆ

69

เป็นเอกสารอย่างเป็นทางการแนะนำของ redux แนะนำให้ส่งออกส่วนประกอบที่ไม่ได้เชื่อมต่อด้วยเช่นกัน

เพื่อให้สามารถทดสอบส่วนประกอบของแอปได้เองโดยไม่ต้องจัดการกับมัณฑนากรเราขอแนะนำให้คุณส่งออกส่วนประกอบที่ไม่ได้ตกแต่ง:

import { connect } from 'react-redux'

// Use named export for unconnected component (for tests)
export class App extends Component { /* ... */ }// Use default export for the connected component (for app)
export default connect(mapStateToProps)(App)

เนื่องจากการส่งออกเริ่มต้นยังคงเป็นองค์ประกอบที่มีการตกแต่งคำสั่งนำเข้าที่แสดงด้านบนจะทำงานเหมือน แต่ก่อนคุณจึงไม่ต้องเปลี่ยนรหัสแอปพลิเคชันของคุณ อย่างไรก็ตามตอนนี้คุณสามารถนำเข้าส่วนประกอบแอพที่ไม่ได้รับการจัดสรรในไฟล์ทดสอบของคุณดังนี้:

// Note the curly braces: grab the named export instead of default export
import { App } from './App'

และถ้าคุณต้องการทั้ง:

import ConnectedApp, { App } from './App'

ในแอปเองคุณจะยังคงนำเข้าได้ตามปกติ:

import App from './App'

คุณจะใช้การส่งออกที่มีชื่อสำหรับการทดสอบเท่านั้น


1
คำตอบนี้ถูกต้องเช่นกัน แก้ไขลิงก์ของคุณเพื่อให้ตรงกับจุดยึด
Erowlin

คำตอบนี้สมเหตุสมผลดี! มันอาจไม่ใช่สิ่งที่ถูกต้องในทุกกรณี แต่ดีกว่าเล่นกับผู้ให้บริการและทุกอย่างที่ไม่จำเป็น
lokori

ขอบคุณ @lokori มีความสุขที่คุณชอบ!
Vishal Gulati

2
นี่เป็นวิธีที่เร็วและง่ายที่สุดในการทำให้การสอบของฉันผ่านอีกครั้ง
Mike Lyons

2
"คุณจะใช้การส่งออกที่กำหนดชื่อเพื่อทำการทดสอบเท่านั้น" - ใช้งานได้สำหรับฉัน
technazi

7

เมื่อเรารวบรวมแอปพลิเคชั่น react-redux เราควรคาดว่าจะเห็นโครงสร้างที่ด้านบนสุดเรามีProviderแท็กที่มีอินสแตนซ์ของที่เก็บ redux

ที่Providerแท็กแล้วทำให้องค์ประกอบที่ผู้ปกครองของคุณช่วยให้เรียกมันว่าAppองค์ประกอบซึ่งจะทำให้ทุกองค์ประกอบอื่น ๆ ภายในแอพลิเคชัน

นี่คือส่วนสำคัญเมื่อเราตัดส่วนประกอบด้วยconnect()ฟังก์ชันฟังก์ชันนั้นconnect()คาดว่าจะเห็นส่วนประกอบหลักบางอย่างภายในลำดับชั้นที่มีProviderแท็ก

ดังนั้นอินสแตนซ์ที่คุณใส่connect()ฟังก์ชั่นในนั้นมันจะค้นหาลำดับชั้นและพยายามค้นหาProviderฟังก์ชั่นในที่นั่นก็จะขึ้นไปดูลำดับชั้นและพยายามที่จะหา

นั่นคือสิ่งที่คุณต้องการที่จะเกิดขึ้น แต่ในสภาพแวดล้อมการทดสอบของคุณที่การไหลเวียนสลาย

ทำไม?

ทำไม?

เมื่อเรากลับไปยังไฟล์ทดสอบ sportsDatabase ที่สมมติขึ้นคุณจะต้องเป็นคอมโพเนนต์ sportsDatabase ด้วยตัวเองและจากนั้นพยายามแสดงองค์ประกอบนั้นด้วยตัวเองโดยแยกออกจากกัน

โดยพื้นฐานแล้วสิ่งที่คุณกำลังทำอยู่ในไฟล์ทดสอบนั้นคือการเอาส่วนประกอบนั้นและทิ้งมันไปในป่าและมันไม่มีส่วนเกี่ยวข้องใด ๆProviderหรือเก็บไว้ข้างบนและนั่นคือสาเหตุที่คุณเห็นข้อความนี้

ไม่มีการจัดเก็บหรือProviderแท็กในบริบทหรือ prop ของส่วนประกอบนั้นดังนั้นส่วนประกอบจะเกิดข้อผิดพลาดเนื่องจากต้องการดูProviderแท็กหรือร้านค้าในลำดับชั้นหลัก

นั่นคือความผิดพลาดนั่นหมายถึง


6

ในกรณีของฉันเพียงแค่

const myReducers = combineReducers({
  user: UserReducer
});

const store: any = createStore(
  myReducers,
  applyMiddleware(thunk)
);

shallow(<Login />, { context: { store } });


2

เพียงทำการนำเข้านี้ {ตื้น, เมา} จาก "เอนไซม์"

const store = mockStore({
  startup: { complete: false }
});

describe("==== Testing App ======", () => {
  const setUpFn = props => {
    return mount(
      <Provider store={store}>
        <App />
      </Provider>
    );
  };

  let wrapper;
  beforeEach(() => {
    wrapper = setUpFn();
  });

2

สำหรับฉันมันเป็นปัญหาการนำเข้าหวังว่าจะช่วยได้ การนำเข้าเริ่มต้นโดย WebStorm ผิด

แทนที่

import connect from "react-redux/lib/connect/connect";

กับ

import {connect} from "react-redux";

1

เรื่องนี้เกิดขึ้นกับฉันเมื่อฉันอัพเกรด ฉันต้องปรับลดรุ่น

react-redux ^ 5.0.6 → ^ 7.1.3


นี่เป็นความคิดเห็นมากกว่า asnwer
sudo97

มีการเปลี่ยนแปลงครั้งใหญ่มากมาย ฉันแนะนำให้ดูวิดีโอนี้เพื่อเข้าใจการเปลี่ยนแปลงของyoutube.com/watch?v=yOZ4Ml9LlWE
Kamil Dzieniszewski

0

ในตอนท้ายของ Index.js ของคุณจำเป็นต้องเพิ่มรหัสนี้:

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter  } from 'react-router-dom';

import './index.css';
import App from './App';

import { Provider } from 'react-redux';
import { createStore, applyMiddleware, compose, combineReducers } from 'redux';
import thunk from 'redux-thunk';

///its your redux ex
import productReducer from './redux/reducer/admin/product/produt.reducer.js'

const rootReducer = combineReducers({
    adminProduct: productReducer
   
})
const composeEnhancers = window._REDUX_DEVTOOLS_EXTENSION_COMPOSE_ || compose;
const store = createStore(rootReducer, composeEnhancers(applyMiddleware(thunk)));


const app = (
    <Provider store={store}>
        <BrowserRouter   basename='/'>
            <App />
        </BrowserRouter >
    </Provider>
);
ReactDOM.render(app, document.getElementById('root'));

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.