Use Redux module inside react component - javascript

I have a module A built in react-redux. A is the parent component name which looks somewhat like
const app = (
<Provider store={store}>
<A />
</Provider>
);
ReactDOM.render(app, document.getElementById('id'));
Inside component A there is a component C.js which has a connect function
A.js
render() {
return (
<div>
<C />
</div>
);
}
C.js
render() {
return(<div>SomeCode</div>
}
export default connect(mapStateToProps, mapDispatchToProps)(C);
There is another B.js file which is a ReactComponent (no redux used here). It has its own state.
I want to use the component A inside B's render method something like
import A from '/path'
render() {
return (<A/>)
}
While doing so I am getting an error.
Could not find "store" in the context of "Connect(C)".
Either wrap the root component in a , or pass a custom React context provider to
and the corresponding React context consumer to Connect(C) in connect options.
Any help appreciated.

I modified parent and exported it as following
render(){
return(
<Provider store={store}>
<A />
</Provider>
);}
Importing A worked fine

Related

How to push a graphql mutation into a component's props properly?

I'm trying to push a graphql mutation into a component's props.
export default graphql(logOnMutation)(Login);
That line of code above doesn't work. No errors showing, but doesn't provide mutate function into props of component.
But if I write like that:
const logOnWithMutation = graphql(logOnMutation)(Login);
export default logOnWithMutation;
and write like this
const App = () => {
return (
<ApolloProvider client={client}>
<Fragment>
<logOnWithMutation/>
</Fragment>
</ApolloProvider>
)
}
it works perfectly.
So what am I missing? I need my first option to work
Decision:
import your Login component in your's parent component as default like that import Login from './containers/login/login'; not through the exact name like import { Login } from './containers/login/login';

how to implement the new react-redux v6.0.0

i was trying to migrate react-redux v5.X.X to v6.0.0 and there dosent seem to be any documentation for it.
i am using following versions :
"react": "^16.4.2"
"redux": "^4.0.0"
"react-redux": "^6.0.0"
the official change log says.
Passing store as a prop to a connected component is no longer supported. Instead, you may pass a custom context={MyContext} prop to both and . You may also pass {context : MyContext} as an option to connect.
link is here
here is my root index.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import { configureStore, history } from './Store';
import App from './App.hot';
import 'antd/dist/antd.min.css';
const reduxStore = configureStore();
ReactDOM.render(<App store={reduxStore} history={history} />, document.getElementById('root'));
here is my app.jsx (root component)
import React from 'react';
import PropTypes from 'prop-types';
import { Provider, connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { ConnectedRouter } from 'connected-react-router';
import Layout from './Layout';
class App extends React.Component {
static propTypes = {
store: PropTypes.object.isRequired,
history: PropTypes.object.isRequired,
};
render() {
const { store, profile, history } = this.props;
return (
<main className="app-wrapper">
// what i understand from change log is this part
// i need to pass context instead of store as props.
<Provider store={store}>
<ConnectedRouter history={history}>
<Layout user={profile} />
</ConnectedRouter>
</Provider>
</main>
);
}
}
function mapStateToProps(store) {
return {
...
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({
...
}, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
as per change log i created context and passed it down to the provider
const storeContext = React.createContext(reduxStore);
here is my render function after that change
render() {
const { store, profile, history } = this.props;
return (
<main className="app-wrapper">
<Provider context={storeContext}>
<ConnectedRouter history={history}>
<Layout user={profile} />
</ConnectedRouter>
</Provider>
</main>
);
}
passing store as props to provider gives following error
Passing redux store in props has been removed and does not do anything. To use a custom Redux store for specific components, create a custom React context with React.createContext(), and pass the context object to React-Redux's Provider and specific components like: . You may also pass a {context : MyContext} option to connect
and passing as context gives following error
Could not find "store" in the context of "Connect(App)". Either wrap the root component in a , or pass a custom React context provider to and the corresponding React context consumer to Connect(App) in connect options.
i did not find any documentation expect this redux history document here it tells all the problems and solutions for the problem in react-redux and how the context api fixed it. but i am not sure how to actually implement it in real project.
did anyone face the same issue ? or can you please tell me how exactly to implement this change.
thanks
I was able to solve the problem by actually listening to what the error message said.
there were two problems with my code
i was passing store as props to my <App /> component. which is why the first warning/error message was comming.
Passing redux store in props has been removed and does not do anything. To use a custom Redux store for specific components, create a custom React context with React.createContext(), and pass the context object to React-Redux's Provider and specific components like: . You may also pass a {context : MyContext} option to connect
to fix this simply dont pass whole redux store as props to any component
my Provider from react-redux was not the root component. the error message said
Could not find "store" in the context of "Connect(App)". Either wrap
the root component in a Provider , or pass a custom React context provider to
and the corresponding React context consumer to Connect(App) in
connect options
so i followed the second wanring in the sentence
Either wrap the root component in a Provider , or pass a custom React context
so i wrapped my main root in provider. and things started working well.
ReactDOM.render(
<Provider store={reduxStore}>
<App />
</Provider>, document.getElementById('root'),
);
I had the same problem and this is how i solved it.
const MyContext = React.createContext();
class App extends Component {
render() {
return (
<Provider store = {store} context={MyContext}>
<BrowserRouter>
<div>
<Main context={MyContext}/>
</div>
</BrowserRouter>
</Provider>
);
}
}

Passing data between External js and React js/Redux

I've integrated React-redux in a externalJs Application (built on custom JS framework). I need to set initial data for redux store from externalJS but, the externalJs is unable to access the react store to set the data. The store gets triggered when the root reactJS component is mounted on the DOM , but i need to set the initial data before its Mounted on the DOM. i referred following links but they were not able to resolve my problem. Can someone please tell me what I am missing?
https://brettdewoody.com/accessing-component-methods-and-state-from-outside-react/
Accessing react components outside
i'm using webpacks, react 16.1 with redux
sample root component structure given below in index.js
render() {
return (
<Provider store={store}>
<Email ref={(EmailComponent) => { window.EmailComponent = EmailComponent }} />
</Provider>
);
}
I'm assuming you're trying to expose EmailComponent and 'store' to the DOM and other frameworks since you are declaring it on a global window object. React.render has a callback as a third parameter which you can use to know when the React App is mounted to DOM.
ReactDOM.render(<App />, document.getElementById('root'), function () {
// now the root React App is mounted and the data from it will be available
// your window.EmailComponent and window.store should now be avialable
console.log(window.EmailComponent, window.store)
})
render() {
window.store = store
return (
<Provider store={store}>
<Email ref={(EmailComponent) => { window.EmailComponent = EmailComponent }} />
</Provider>
);
}

How to test a React component that has Router, Redux and two HOCs... with Jest and Enzyme?

I am currently unable to find a solution to this problem.
I have a React Component that is connected to React Router 4, Redux store and is wrapped by two HOCs. Its pretty crazy, but this is how it was coded.
Here is the export to give you an idea:
export default withFetch(Component)(fetchData, mapStateToProps)
I am trying to run some basic tests on it:
it('should render self and subcomponents', () => {
const wrapper = shallow(<Component {...props} />)
expect(toJson(wrapper)).toMatchSnapshot()
})
Which outputs a console.log/snapshot of:
<Route render={[Function: render]} />
Things tried but no succeed:
I've tried wrapping my component in the Memory Router
Supply a redux store to the component
Used .dive() and .chilndren() to try and see the children
Tried mount and render with no success.
Still keeps rendering the <Route render={[Function: render]} />
Trying out :
<MemoryRouter>
<Component {...props} />
</MemoryRouter>
Still produces the same result.
Note that I've also tried importing my component as
import { Component } from './components/'
But it returns undefined.
Any help is deeply appreciated. Thank you! šŸ˜ŠšŸ™
I assume that by <Router> you are referring to BrowserRouter.
The best way is to isolate the wrapped component and test it with testing alternatives.
For example assume that you want to test that:
// App.jsx
export const App = () =>
<Router>
<ReduxProvider>
<AppInner>
</ReduxProvider>
</Router>
My suggestion is to test AppInner with testing env of Router & ReduxProvider.
In tests:
// AppInner.test.jsx
import {mount} from 'enzyme';
import {MemoryRouter} from 'react-router';
describe('AppInner', () => {
it('should do something', () => {
const TestingComponent = () =>
<MemoryRouter>
<ReduxProvider>
<AppInner />
<ReduxProvider>
<MemoryRouter>;
const component = mount(TestingComponent);
});
})
Pay attention that I've wrapped the AppInner with MemoryRouter, it allows your mimic router but without the dependency of the browser.
For more info you can read the testing section of react-router;

How to test a component with a nested container with React and Redux?

Due to the complexity of the application I am working on I have decided on using a nested redux container rather than passing an action as a prop down to the child components. However, this has proved to be problematic for unit testing when rendering the OuterContainer with jsdom in combination with mocha, chai and sinon.
Here is a contrived example of the view structure:
<OuterContainer>
<div>
<InnerContainer />
</div>
</OuterContainer>
where OuterContainer & InnerContainer are wrapped with connect. e.g.:
export connect(<mapStateToProps>)(<Component>)
When running tests the error I am getting is:
Invariant Violation: Could not find "store" in either the context or props of "Connect(Component)". Either wrap the root component in a `<Provider>`, or explicitly pass "store" as a prop to "Connect(Component)".
Is there a way to unwrap or stub the InnerContainer for unit testing without having to use shallow rendering?
Wrap your component in <Provider> when testing. Itā€™s up to you whether to supply a real store or a mock with { dispatch, getState, subscribe } to it. Wrapping the outermost component in <Provider store={store}> will also make the store available to the child components at any level of nestingā€”just like in the app itself.
const store = createStore(reducer) // can also be a mock
ReactTestUtils.renderIntoDocument(
<Provider store={store}>
<OuterContainer />
</Provider>
)
Another approach is to export both the component to be connected and the container. The container as default, of course.
export const Comp = (props) => (<p>Whatever</p>)
export default connect(...)(Comp)
Hence, you can unit test Comp.
Not sure if this is what your problem is, but I'm sure this will probably help a few people out there looking at this feed.
I had the same error and it was a simple fix:
I had forgotten to pass my component my store object in my entry file (using webpack).
I just added an attribute to the Root component "store={store}" see below:
document.addEventListener("DOMContentLoaded", () => {
const store = configureStore();
ReactDOM.render(<Root store={store} />,
document.getElementById('content'));
});
This was my root file code for reference as well:
import React from 'react';
import { Provider } from 'react-redux';
import App from './app';
const Root = ({ store }) => (
<Provider store={ store }>
<App />
</Provider>
);
export default Root;
Hope that helps someone!
Mock the Provider component to return the child component.
Add this before describe().
jest.mock('Provider', () => ({children}) => children);

Categories