Context not passed through redux connect ()

Edit: I was able to connect the child update to a context change with a Redux troubleshooting suggestion when installing { pure: false } , however I needed to add this to all the connected components that the child’s parents want to be updated. It seems strange and ineffective to do this with a lot of components.


First of all, I will describe what my desired end result is before I dive into what I think of the problem.

I want to access settings to adjust the router from within the grandson component of my Route component. There are several links that say that there is no need to synchronize the current route with the store if you do not use “recording, saving and playing back user actions while traveling” , so I have avoided it so far. Dan Abramov states here that it’s normal that they do not synchronize and simply use the route as a source of truth.

Similar questions that do not have answers to my problems: https://stackoverflow.com/a/212877/
Passing through context with <Provider> does not work in connect () based script

Since response-router does not provide the current parameters as a context, I decided to add the current parameter as a context from the Route component. I can access the context right up to the component tree until I reach the Child that was configured with connect () . Initial page rendering gives the child the right context. However, when the context changes, the child is not updated. connect () seems to remove the context link.

Is this the desired connect () behavior? If so, how should the component access the route parameters without synchronization with the repository?

Here is a JSFiddle showing a very minimal scenario when the context is not updated past the “connected” component.

Here is some of my actual code where I send the current route parameter as context from the router component ( /view/:viewSlug ). I tried to install the component { pure: false } in connect , as described in troubleshooting abbreviations but no luck.

Component Parent (App)

 class App extends Component { getChildContext() { const { viewSlug } = this.props return { viewSlug } } ... } App.PropTypes = { ... } App.childContextTypes = { viewSlug: PropTypes.string } ... export default connect(mapStateToProps)(App) 

Grandchild Container (Day)

 import Day from '../components/Day' const mapStateToProps = (state, ownProps) => { ... } export default connect(mapStateToProps)(Day) 

Grandchild Component (Day)

 class Day extends Component { ... } Day.PropTypes = { ... } Day.contextTypes = { viewSlug: PropTypes.string.isRequired } export default Day 
+8
javascript reactjs redux react-router react-redux
source share
3 answers

After a quick discussion with Dan Abramov, there seems to be no good way to pass parameters down to various deep components. ( Discussion here ). Once React Router 3.0 is released, it will be very trivial for a proper implementation.

Temporary solution

Currently, the only workaround I have found is to install a child component, as well as any predecessor components between the child component and the route component as an “unclean” component.

This can be done using the options parameter when using the connect () function.

 export default connect(mapStateToProps, null, null, { pure: false })(MyComponent) 

This information was found on the Redux troubleshooting page.

+7
source share

I have the same problem: I have a language setting in the route path that I store as context and use in all components of my application. And when I mount the redux repository, the context properties are no longer updated.

As you already mentioned, there is an argument { pure: false } to force the component to retransmit more time than necessary.

Another solution is not to use context. You can use react-router-redux to save and update the changed URL in the Redux store. This has its own LOCATION_CHANGE action, which has a payload object:

 routing: { locationBeforeTransitions: { pathname: 'view/someView', search: '', … } } 

It has no parameters at the moment, but you can parse the pathname and get them in the old school style regexp. :)

And please read this issue, there are other ways: https://github.com/facebook/react/issues/2517

UPDATE:

There is another way: save the state of the application in the redux store:

 import { setCurLang } from '../actions/langActions'; const App = React.createClass({ componentWillMount(){ this.props.actions.setCurLang(this.props.params.curLang); }, shouldComponentUpdate: function(nextProps) { return nextProps.params.curLang !== this.props.params.curLang; }, componentWillUpdate(nextProps) { this.props.actions.setCurLang(nextProps.params.curLang); }, render() { return ( <div> {/* here you can use your saved URL-param as prop, and it will be updated each time react router changes */} {this.props.curLang} </div> ) } }); function mapStateToProps(state) { return { curLang: state.curLang } } function mapDispatchToProps(dispatch) { return { actions: bindActionCreators( { setCurLang }, dispatch) } } export default connect(null, mapDispatchToProps)(App); 

my reducer (this is simplified, of course, you can use combineReducers here):

 const curLang = 'de'; export default function reducer(state = curLang, action) { switch (action.type){ case 'SET_CUR_LANG': return { ...state, cur: action.curLang } default: return state; } } 

and action:

 export function setCurLang(curLang) { return { type: 'SET_CUR_LANG', curLang: curLang } } 
0
source share

The reason we are not this.context when we use this.context -redux connect () is because we do not specify contextTypes check this comment

Add contextTypes like this:

 import PropTypes from 'prop-types'; Myapp.contextTypes = { store: PropTypes.object }; 

Now we can find that this.context matters and the store is available at this.context.store

Check this comment for more illustration.

0
source share

All Articles