Passing data between External js and React js/Redux - javascript

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>
);
}

Related

Use Redux module inside react component

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

Shallow render a component which is a class that uses context

I am trying to test a component using shallow with enzyme. The component I am trying to test is a class and doing context like so:
class ExampleComponent extends Component {
static contextType = AppContext;
...
and using it in that component const { url } = this.context;
When writing the test this has been used:
const contextWrapper = {
wrappingComponent: AppContext,
wrappingComponentProps: { url: 'http://appUrl.com' },
};
and here is the snapshot test as an example which is using mount as this seems to be the only way to get context to work.
it('should render correctly', () => {
const output = mount(<Comonent {...props} />, contextWrapper);
expect(shallowToJson(output)).toMatchSnapshot();
});
I have done some refactoring and in this file there is a component which is connected to the store. When using mount it expects a store to be provided to that component which is why I would like to us shallow.
If I wrap Component with a <Provider store={store}> I can get this to all work but I have a test further down trying to access state on Component but it is blank and can't find it.
Here is a snippet of the test where state is not found:
const output = mount(
<Provider store={store}>
< ExampleComponent {...newProps} />
</Provider>,
contextWrapper,
);
expect(output.state('stateValue')).toBe(true);
and this is the error shown:
ReactWrapper::state("stateValue") requires that `state` not be `null` or `undefined`
Is there a way to use shallow and context? I have found this package to 'fix' it for now shallow-with-context but I am not sure if that is correct? I have also seen old posts saying enzyme doesn't support the new context api. is that correct? What is the best method to solve this issue?

How to use React Context API with redux?

I have a react redux application that I want to use React Context API for one of the things I'm trying to do
so I have this
<Provider value="something" store={store}>
// stuff in here
</Provider>
which works fine but then I tried to add context
const AppTypeContext = React.createContext('someContext' as any)
<AppTypeContext.Provider value="myValue" store={store}>
// stuff in here
</AppTypeContext.Provider>
then my app threw an error saying Property 'store' does not exist on type 'IntrinsicAttributes & ProviderProps<any>'. TS2322
how do I fix this? and what provider do I need to use?
The app can have multiple contexts.
Just separate properly the provided values:
store is to be provided via Provider
"something" should be provided by your AppTypeContext.Provider.
<Provider store={store}> // redux provider
<AppTypeContext.Provider value="something"> // your provider
{children}
</AppTypeContext.Provider>
</Provider>

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>
);
}
}

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