Store subscribe not working in external component - javascript

So technically I have 2 components, I dispatch event from 1st, I want detect this change in 2nd.
I did everything as in Redux docs about Store subscribing : https://redux.js.org/api/store#subscribe. Unfortunatelly, it's not working for me.
This is my 1st react project.
(vue/x is better :] )
import React, {Component} from 'react';
import reducers from '../../reducers'
import { Dropdown } from 'semantic-ui-react'
import {translate} from "../../actions";
import createStore from "../../createStore";
const store = createStore(reducers)
class Component1 extends Component {
componentDidMount() {
store.subscribe(() => console.log(1));
}
updateTexts(lang) {
store.dispatch(translate(lang));
}
render() {
this.dropdown = <Dropdown
onChange={this.updateTexts}
/>
return (
<div className={"lang-switcher"}>
<div className={"select-lang"}>
{this.dropdown}
</div>
</div>
);
}
}
export default Component1
import React, {Component} from 'react';
import axios from 'axios';
import {Animate} from 'react-animate-mount';
import createStore from "../../createStore";
import reducers from "../../reducers";
const store = createStore(reducers);
export default class Component2 extends Component {
componentDidMount() {
store.subscribe(console.log(2));
}
render() {
return (
<div className="box">
{Something}
</div>
);
}
}
I want that Component2 will detect state change done by Component1.
Reducer is working correctly, updates state after dispatching.

If you're using React, you should be using the React-Redux library to handle interacting with the store.
That said, it also looks like you're creating two different store instances, one in each component file. So, Component 2 doesn't know about the store instance in Component 1's file.

Please create a script Store.js, and import for each component.
When you use export, that will create a singleton from your export const:
Store.js
import reducers from '../../reducers'
import createStore from "../../createStore"
export default createStore(reducers)
and use as:
import store from "./Store";
/* REMOVE const store = createStore(reducers); */

Related

How to dynamically call a module in React Native

I would like to have a react native View dynamically added. This will be completely undetermined before calling.
import React, {Component} from 'react';
import {View} from 'react-native';
export default class HelloWorld extends Component {
render() {
return (
<View>{ /** add a component a view depending on paremeters passed into class in Props**/}</View>
);
}
}
Since this will be completely undetermined I am not sure how to call a module from another module without first importing it.
How can I go about it?
Thank you all in advance.
How to dynamically call a module in React Native
import React, {Component} from 'react';
import {View} from 'react-native';
export default class HelloWorld extends Component {
render() {
let dynamicComponent = this.props.displayDynamicComponent ? <DynamicComponent /> : null;
return (
<View>{dynamicComponent}</View>
);
}
}

createProvider is not exported from react-redux?

I am trying to create multiple distinct Redux stores, for that am using createProvider() method in 'react-redux'.
I have installed the latest react-redux version(7.1.0), but am getting the error like "createProvider is not exported from react-redux". When i gone through the node modules, i couldn't able to find the createProvider inside the src of react-redux. Is it a version issue or did i miss something in the code. I have shared you the following code snippet as :
Provider.js
import { createProvider } from "react-redux";
export const STORE_KEY = "myComponentStore";
export const Provider = createProvider(STORE_KEY);
TestComponent.js
import React, { Component } from "react";
import { createStore } from "redux";
import Mycomponent from "./MyComponent";
import { Provider } from "./Provider";
const reducer = {};
const initialState = {
title: "multiple store"
};
const store = createStore(reducer, initialState);
class TestComponent extends Component {
render() {
return (
<Provider store={store}>
<Mycomponent />
</Provider>
);
}
}
export default TestComponent;
Mycomponent.js
import React, { Component } from "react";
import { connect } from "./Connect";
class MyComponent extends Component {
render() {
return <div>{this.props.title}</div>;
}
}
export default connect(function mapStateToProps(state) {
return {
title: state.title
};
})(MyComponent);
Seems like it is deprecated and removed since V6
Your store could be something like this:
// store.js
import { createStore } from 'redux';
import rootReducer from './root-reducer';
export default createStore(rootReducer);
And that "rootReducer" is a combination of different reducer files:
//root-reducer.js
import SomeReducers from './reducers/some-reducers';
import AnotherOne from './reducers/another-one';
const rootReducer = combineReducers({
SomeReducers,
AnotherOne,
})
export default rootReducer;
Then your store is used in the index
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from "react-redux";
import store from "./storage/store";
import App from './App';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById('root')
);
But it still just one store
In documentation, it says
Don't create more than one store in an application! Instead, use
combineReducers to create a single root reducer out of many.
So one provider, one store and multiple reducers are the correct(recommended) way to use redux. Create one global provider for your application and define your reducers for that provider. You can use data selectors for your components.
For this information probably dev team decided to deprecate createProvider functionality.
I am trying to create multiple distinct Redux stores
It's fine to have multiple and distinct Redux stores in a single React application. Just don't use createProvider() for it. The two approaches to having multiple independent Redux stores are:
Use Redux sub-apps:
SubApp5.js
----------
const store = createStore(reducer)
return {
<>
<Provider store={store}>
<MyTable />
</Provider>
</>
}
With this approach multiple Redux stores will coexist.
Use multiple SPAs inside a single React application - see crisp-react. With this approach multiple Redux stores will not coexist.When you build crisp-react, it creates a React application with 2 SPAs and you can add Redux to each SPA. Then you can switch from one SPA (and its Redux store) to another SPA and its store.

Function components do not support contextType

Function components do not support contextType.
I encountered an issue when trying to add context to a React component that was wrapped with a React Router withRouter(...) function.
import React, { Component } from 'react'
import UserContext from './UserContext'
class Toolbar extends Component {
render(){
return (
<div>username: this.context.username</div>
)
}
}
Toolbar.contextType = UserContext
export default withRouter(Toolbar)
The solution to this issue is simply switch the last two lines like so:
export default withRouter(Toolbar)
Toolbar.contextType = UserContext

How to call mapStateToProps in react component to get Redux stores

I am trying to get the Redux state that is stored to be set to a component's props. My components implementation is below
import React, { Component } from 'react';
import {connect} from 'react-redux';
class Characters extends Component {
render() {
console.log('props', this.props);
return(
<div>
<h4>Characters</h4>
</div>
)
}
}
const mapStateToProps = state => {
return {
characters: state.characters
}
}
export default connect()(Characters);
I have my reducers set up like following. Now my console.log() is printing out a dispatch object not the props. I am not sure what else I need to do to set the component's props. I have tested my reducers and they seem to work fine. I am having trouble setting the component's props to the redux store. Below is my main reducer.
import { combineReducers } from 'redux';
import characters from './characters_reducer';
import heroes from './heroes_reducer';
const rootReducers = combineReducers({
characters,
heroes
});
export default rootReducers;
Not sure what am I doing wrong here. A little help and a hinge to the right direction would help a lot. Thanks :)
You forgot to pass mapStateToProps to connect:
export default connect(mapStateToProps)(Characters);
You need to pass in your actionCreators and your mapStateToProps function to the connect function in order to be able to access the store from the component:
export default connect(mapStateToProps)(Characters);

How can I write a unit test for a react component that calls reduxjs's mapStateToProps?

I'm trying to write unit tests for a container component called AsyncApp but I get the following error "mapStateToProps must return an object. Instead received undefined."
This is my set-up.
Root.js
import configureStore from '../configureStore';
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import AsyncApp from './AsyncApp';
const store = configureStore();
export default class Root extends Component {
render() {
return (
<Provider store={store}>
<AsyncApp />
</Provider>
);
}
}
configureStore.js
import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import createLogger from 'redux-logger';
import rootReducer from './reducers';
const loggerMiddleware = createLogger();
const createStoreWithMiddleware = applyMiddleware(
thunkMiddleware
//loggerMiddleware
)(createStore);
export default function configureStore(initialState) {
return createStoreWithMiddleware(rootReducer, initialState);
}
AsyncApp.js
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { foo } from '../actions';
import FooComponent from '../components/FooComponent';
class AsyncApp extends Component {
constructor(props) {
super(props);
this.onFoo= this.onFoo.bind(this);
this.state = {}; // <--- adding this doesn't fix the issue
}
onFoo(count) {
this.props.dispatch(foo(count));
}
render () {
const {total} = this.props;
return (
<div>
<FooComponent onFoo={this.onFoo} total={total}/>
</div>
);
}
}
function mapStateToProps(state) {
return state;
}
export default connect(mapStateToProps)(AsyncApp);
I'm passing store directly to AsyncApp in my test to avoid getting the following Runtime Error : Could not find "store" in either the context or props of "Connect(AsyncApp)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(AsyncApp)".
The test isn't complete yet because I can't get past the mapStateToProps error message.
AsyncApp-test.js
jest.dontMock('../../containers/AsyncApp');
jest.dontMock('redux');
jest.dontMock('react-redux');
jest.dontMock('redux-thunk');
jest.dontMock('../../configureStore');
import React from 'react';
import ReactDOM from 'react-dom';
import TestUtils from 'react-addons-test-utils';
const configureStore = require( '../../configureStore');
const AsyncApp = require('../../containers/AsyncApp');
const store = configureStore();
//const asyncApp = TestUtils.renderIntoDocument(
//<AsyncApp store={store} />
//);
const shallowRenderer = TestUtils.createRenderer();
shallowRenderer.render(<AsyncApp store={store}/>);
I want to eventually test that AsyncApp contains a FooComponent, and that a foo action is dispatched when onFoo is called.
Is what I am trying to do achievable? Am I going about this the right way?
The suggestion I've seen in a few places is to test the non-connected component, as opposed to the connected version. So, verify that when you pass in specific props to your component you get the expected rendered output, and verify that when you pass in a state with a certain shape your mapStateToProps() returns the expected pieces. Then you can expect that they should both work correctly when put together.

Categories

Resources