-
-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Will it be exposed ReactReduxContext from react-redux? #935
Comments
You'll still be using |
@markerikson it would be safe to share ReactReduxContext.Consumer for such demands |
What's your use case? Why do you need access to the store itself elsewhere in the component tree? |
@markerikson |
@markerikson we really need access to store.replaceReducer |
@budarin No changes have been made or will be made in the near future. We have no idea how things will actually shake out. |
so we have to make an additional context that will duplicate the existing redux internal context - it's overhead |
at now we have this ugly code return (
<Provider store={store}>
<StoreContextProvider store={store}>
.....
</StoreContextProvider>
</Provider>
); |
The store is made available to your connected components. You don't need to add your own context. |
@timdorr store.replaceReducer(...) |
Hi, im having similar issue trying to make redux code split reducers. @budarin @timdorr @markerikson |
Our current WIP v6 PRs at #995 and #1000 both actually put both the store and the store state into context. I don't think we're going to officially support accessing it, but I don't want to intentionally block people from accessing it either. Beyond that, please try out the PRs and give us feedback on how well they work (or don't work)! |
@jwugit I've found on the internet a snippet from Dan Abramov but I lost the link |
@markerikson @budarin But my specific uses case is having multiple store and i cannot use the singleton approach since i wouldnt be able to target the correct store instance. @markerikson @budarin Initially i thought this would be a react problem since it is changing the legacy context to new context api. But Dan mention it's more of a react-redux decision of letting context be exposed or not in the upcoming updates. So here i am 😃 . |
@jwugit : can you give some specific examples of how and why you have multiple stores in your app, and what the component tree looks like (ie, which components are needing to pull data from which stores)? |
@markerikson Now i dont want the store data to be sync, other wise updating one will update all the other.
For option 1, is easy with only 2 component pages, but what if i have 20+ pages. Then there will be too many reducers times the number of roots i have. So we opt to try option 2. its cleaner to see in the redux dev tool also, and we name each generated one. So basically each root level app needs to pull data from its own store. `
}); |
i realize that with the updated react context api, My flow: app container
loadable
fruit component
withReducer
Based on this legacy context example, |
It's true that in a big enterprise app store should have an ability for dynamic injecting/rejecting some reducers djue to a large amount info stored in it. |
@markerikson |
@jwugit : we really haven't gotten that far. Give us some time to figure out how the rest of React-Redux v6 will behave, and hopefully we can address your concerns once the rest of the implementation is sorted out. |
Yes: Line 6 in 59aaba5
|
tested the beta and its working great! |
@jwugit I have the same kind of problem. Not using Loadable, but Currently, my only dirty patch is to call:
In the Thank you, |
@GuillaumeCisco : that sounds very wrong. What are you actually trying to accomplish? Why are you needing to try to hack into the context like that? What does the rest of your code look like? |
@GuillaumeCisco i'm not sure if youre referring to the same issue i mentioned on this ticket. but when i run replaceReducer to update the store, everything is recreated in the store, this is the create store function in my proof of concept app.
|
Thank you @jwugit . I'm not sure too now ^^" But there is a lot of similitude. I use Basically
So basically, if I want to inject a Component in my app and inject its reducer too, I simply write: import React from 'react';
import universal from 'react-universal-component';
import {injectReducer} from 'redux-reducers-injector';
const UniversalComponent = universal(import('./my_component.js'), {
onLoad: (module, info, props, context) => {
injectReducer('loadingReducer', module.loadingReducer); // will call replaceReducer
}
});
export default UniversalComponent; The file import React, {Component} from 'react';
import {connect} from 'react-redux';
// make loadingReducer available for being injected
export loadingReducer from './loadingReducer';
class MyComponent extends Component {
render () {
const {loading} = this.props;
return loading ? <span>loading</span> : <div>my heavy content</div>;
}
}
const mapStateToProps = (state, ownProps) => ({
loading: state.loadingReducer.loading,
});
export default connect(mapStateToProps)(MyComponent); This works perfectly with As I read from react-redux 6.0.0 Behavior changes here:
Si I don't know really how to be able to pass the last state to my component with its injected reducer available. Is there some documentation about that? Furthermore, As I expected, the fourth parameter Thank you, |
@GuillaumeCisco I'm not familiar with react-universal-component Does this mean the inject happens after loading ? |
Thank you @jwugit, It confirms what I understand about it. But it seems according to the documentation of See: https://github.com/faceyspacey/react-universal-component
When reading carefully: Furthermore, looking at the sample code on this method, we understand very well it was created for handling this kind of behavior: injecting reducer/saga before rendering the component. I do not know how to fix this kind of issue, do you think it is now a Thank you, |
@GuillaumeCisco |
@jwugit : no, function replaceReducer(nextReducer) {
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.')
}
currentReducer = nextReducer
dispatch({ type: ActionTypes.REPLACE })
} |
Yes I can confirm the reducer is well injected. |
@markerikson thanks for clarifying. @GuillaumeCisco
usage sample:
How you load it should not be an issue. |
Thank you @jwugit for your code. I tried to make it works with I then created a new way to replace the reducers looking at your code. It still does not work. Is there an easy way to update the First of all, I think Thanks, |
Ok folks, after a lot of try and fail playing with the new React Context philosophy and the Tell me if all my assertions are correct:
With this in mind, how to create a HOC which can I understand now why my dirty patch was working: Using I'm still learning how to use React Context correctly, but I don't see any way to correctly update the context, except than using Thank you for your corrections, |
@GuillaumeCisco You should dispatch an action like you would normally do with Redux. But if you're replacing the reducer, Redux will do that for you: https://github.com/reduxjs/redux/blob/master/src/createStore.js#L227 |
Thank you @timdorr . Here is a draft for a HOC which should update the reducers: import React, {Component} from 'react';
import {ReactReduxContext} from 'react-redux';
import {combineReducers} from 'redux';
import set from 'lodash/set';
import has from 'lodash/has';
const combine = combineReducers;
export function combineReducersRecurse(reducers) {
// If this is a leaf or already combined.
if (typeof reducers === 'function') {
return reducers;
}
// If this is an object of functions, combine reducers.
if (typeof reducers === 'object') {
let combinedReducers = {};
const keys = Object.keys(reducers);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
combinedReducers[key] = combineReducersRecurse(reducers[key]);
}
return combine(combinedReducers);
}
// If we get here we have an invalid item in the reducer path.
throw new Error({
message: 'Invalid item in reducer tree',
item: reducers,
});
}
const LoadReducer = (store, storeState, keyName, reducer, props) => (WrappedComponent) => {
class Consumer extends Component {
constructor(props) {
super(props);
if (!storeState[keyName]) {
if (!has(store.injectedReducers, keyName)) {
set(store.injectedReducers, keyName, reducer);
}
store.replaceReducer(combineReducersRecurse(store.injectedReducers)); //should dispatch an action and call mapStateToProps with new state
}
this.state = {
store,
storeState: store.getState(),
}
}
render() {
return !this.state.storeState[keyName] ? <div>loading</div> : <WrappedComponent {...props}/>
}
}
return <Consumer/>
};
export const withReducer = (key, reducer) => (WrappedComponent) => {
return (props) => {
return (
<ReactReduxContext.Consumer>
{({store, storeState}) => {
return LoadReducer(store, storeState, key, reducer, props)(WrappedComponent);
}}
</ReactReduxContext.Consumer>
);
};
}; I call it like: const mapStateToProps = (state) => ({
item: state.item.name,
});
export default withReducer('item', reducer)(connect(mapStateToProps)(Comp)); The first parameter |
@GuillaumeCisco If you inspect the redux in dev tools, you will see that there are 2 reducers. Then navigate to fruit page. So basically existing states is preserved, new reducer are injected before component is loaded. For me it works. |
will there be a new syntax of context available for using in my HOCs or should I using connect for accesing store and reinventing another one context?
The text was updated successfully, but these errors were encountered: