I am using react, styleguidist and redux. I am trying to document different app states depending on redux store state, but the playground the .md file creates only uses one store. The .md file looks like this:
import * as actions from './redux/actions';
import { Provider } from 'react-redux'
import store from './redux/store';
(
<Provider store={store}>
<App />
</Provider>
)
in the same .md file there is another .js block, as the example [here]:(https://react-styleguidist.js.org/docs/documenting.html#usage-examples-and-readme-files)
the block is :
import * as actions from './redux/actions';
import { Provider } from 'react-redux'
import store from './redux/store';
// the live sample in the styleguidist server updates correctly when dispatching the action
store.dispatch(actions.showConnection(true));
//THE PROBLEM IS THAT THE OTHER SAMPLE (THE ONE ABOVE) ALSO UPDATES) so there is one store for the entire sample
//¿How can I dispatch actions and only update the sample inside each ``` js code?
//¿How can I mock the redux store inside each js block sample in the .md file ?
(
<Provider store={store}>
<App />
</Provider>
)
any help will be appreciated.
Related
I am using React-Redux, but I am not able to figure out how to access a variable in the Redux store inside of my nested components.
How can I share a variable between components, using React-Redux?
For example:
I have an 'index.js' file and 30 nested components. Managing these components becomes difficult after a while.
I have a 'C1.js' component. Let's just say I wrote this code in it.
function Reducer(state = 'example' , action) {
return state;
}
const store = createStore(Reducer)
index.js file:
<Provider store = {store}>
<App/>, document.getElementById('root')
</Provider>
How do I pass the 'store' variable to the 'C1.js' component to the index.js file?
Thanks...
You need to use something called "Connect" to connect your various components to the provider.
In the file that contains your C1.js component:
import {connect} from 'react-redux'
const MyComponent = () => {
let someData = props.someData
return(
//all of your JSX for your component here
)
}
const mapState = state => {
return {
someData: state.someData
}
}
export default connect(mapState)(MyComponent)
In the code above, notice the mapStateFunction. Connect is hooking that up with the Provider, and the state that is on the Provider. So that is where you are able to link whatever properties are on your Provider (React-Redux) state with this particular data.
Now, in your component, you will now have prop.someData
-
In the index file, you have your Provider in the wrong place, you need to change your code to this:
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('app')
)
See, the difference there? The is the React Element (and all of its children that you are asking React to render to the DOM). It is the first parameter of the ReactDOM.render function.
The second parameter to the ReactDom.render function is the element in the DOM where you want it to put all of your React elements.
You did not configure well redux and react. You need to go over the doc of redux to setup correctly. Should get working after that.
Is it possible to ES6 import a React component from node_modules that depends on a Context Provider (like react-redux 6.0) without the Provider Context being exported by that module?
For example, the implementation of the import would wrap the imported component with its own Provider.
import App from 'app-package'
import { Provider } from 'react-redux'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('example'),
);
this works in react-redux 5.1.1 but not in 6.0.0, I assume because 6.0.0 is now using the React Context API. The problem may also be webpack related.
Found this https://github.com/facebook/react/issues/13336.
It seems that <App/> must have its own Provider Context since it is outside of the imperative boundary.
To share store with <App/>, one can use ReactReduxContext.Consumer and pass store as a prop to it (via a component wrapper)
I'm trying to upgrade to Redux V6 but am confused on how to use the createContext function and it's necessity. I know my store is created successfully, but when I try to run my app I get
Could not find "store" in the context of "Connect(ConfiguredApp)".
Either wrap the root component in a , or pass a custom React
context provider to and the corresponding React context
consumer to Connect(ConfiguredApp) in connect options.
Which tells me that my provider is not properly passing down the store for connect to grab. What am I doing wrong? Thanks!
import 'babel-polyfill';
import React from 'react';
import {render} from 'react-dom';
import {Provider} from 'react-redux';
import {ConnectedRouter} from 'connected-react-router';
import {history, store} from './store/store';
import Routes from './routes';
const customContext = React.createContext(null);
render(
<Provider store={store} context={customContext}>
<ConnectedRouter history={history} context={customContext}>
<Routes />
</ConnectedRouter>
</Provider>, document.getElementById('app'),
);
You almost definitely shouldn't be creating and passing in a custom context instance. That's only if, for some very specific reason, you want to use a context instance other than the default one that React-Redux already uses internally. (A hypothetical reason to do this would be if you are using one store for your whole app component tree, but there's a specific subtree that needs to receive data from a different store instead.)
If you actually wanted to use your own custom context instance, then you would need to pass the same context instance to both <Provider> and each connected component in the app that needs to receive data from that <Provider>.
Looking at the connected-react-router docs, they do claim that in CRR version 6, you can pass a context instance to <ConnectedRouter>, but that shouldn't be necessary here.
More specifically, if you look at the error message, it says the problem is in Connect(ConfiguredApp). So, it's your own connected component that is saying there's a context mismatch.
Ultimately, the answer here is to delete the context arguments from both <Provider> and <ConnectedRouter>. You don't need them.
Using create-react-app
//index.js
...
export const store = createStore(getChange, applyMiddleware(thunk))
//getChange is my reducers name
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById('root'));
registerServiceWorker();
// Box.js which gets rendered in App.js
import {store} from '../../../index'
...
const renderagain = () => store.getState()
store.subscribe(renderagain)
...
This throws me an error
TypeError: Cannot read property 'subscribe' of undefined
Excuse me? What am I doing wrong?
It's a circular dependency issue.
index.js imports App.js, which eventually imports Box.js. But, Box.js is attempting to import {store} from "../../index.js", which is wrong in several ways.
Your component files should not be attempting to import the store directly, and definitely should not be attempting to import values from index.js. You also shouldn't be trying to subscribe to the store directly in your component files.
Instead, use the React-Redux connect() function in your components to create wrappers that manage the process of subscribing to the store for you. Then, use the connected components, and they'll automatically use the store you passed to <Provider>.
//index.js
...
export const store = createStore(getChange, applyMiddleware(thunk))
//getChange is my reducers name
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById('root'));
registerServiceWorker();
the code above is good to be used to create a store with some reducers combined. and also providing that tot he whole application by passing it into the Provider Component wrapping the Application. This makes the redux actions and store contents available to access for the component. There you can subscribe the store to et notified on changes in store, or on action dispatches.
You are using the callback to subscribe in a wrong way. You might use it this way:
function select(state) {
return state.some.deep.property
}
let currentValue
function handleChange() {
let previousValue = currentValue
currentValue = select(store.getState())
if (previousValue !== currentValue) {
console.log(
'Some deep nested property changed from',
previousValue,
'to',
currentValue
)
}
}
const unsubscribe = store.subscribe(handleChange)
unsubscribe()
For further documentation and queries you can see this. https://redux.js.org/api/store#subscribe-listener
Is there any way to create an action in your MobX store, which pushes your app to a new url using react router v4, e.g. this.props.history.push...
I constantly get a history undefined error, but am unsure how to access the history from my store.
The history push called from the component itself does work though..
many thanks! (this is driving me crazy..)
Since I stumbled across the same issue, I'll share my solution. I just put the RouterStore into its own file in my stores directory, then if I needed access to history or location or whatever, I would import the routing store into the store I was currently working in.
./stores/routing.ts
import { RouterStore } from 'mobx-react-router'
export default new RouterStore()
./stores/other-store.ts
import routing from './routing'
export class OtherStore {
#action
doSomething = () => {
routing.push('/new-route')
}
}
export default new OtherStore()
./index.ts
import { Router } from 'react-router-dom'
import { Provider } from 'mobx-react'
import createBrowserHistory from 'history/createBrowserHistory'
import { syncHistoryWithStore } from 'mobx-react-router'
import otherStore from './stores/other-store'
import routing from './stores/routing'
const browserHistory = createBrowserHistory()
const stores = {
otherStore,
routing,
}
const history = syncHistoryWithStore(browserHistory, routing)
ReactDOM.render(
<Provider {...stores}>
<Router history={history}>
<App />
</Router>
</Provider>,
document.getElementById('root'),
)
You can use mobx-react-router to put react-router in a mobx store and then use it by injecting it in components.
You can also pass the router store as a constructor argument to your other stores that need it. This way you have the router history instance available in your mobx store.
I would like to add a simpler solution that does not require any additional libraries. React Router version is 5.2
Among my stores i've created a HistoryStore.js with the following code:
import { createBrowserHistory } from 'history';
export class HistoryStore {
history = createBrowserHistory();
}
Then I create an instance of it in my contexts.js file but you could do it right away.
export const history = new HistoryStore();
After that you import it in your index.js and pass it as a history prop to the Router.
That's it. Now you could import this store into any other and use it there. When you use useHistory hook in your component it gets this history object, so your history in synchronized.