1
votes

I've made this sample app to learn how I can using react-router-dom and redux together, everything is working except, I don't see how I can access props inside a component?

All the code is here https://gist.github.com/kristiannissen/b9a9ef1904eb40af9c305e06af4cf0fc

Entry file index.js

import { render } from 'react-dom'
import React from 'react'
import { Provider } from 'react-redux'
import { ConnectedRouter } from 'react-router-redux'

import App from './app'
import { store, history } from './store'

render(
    <Provider store={ store }>
        <App />
    </Provider>, document.getElementById('app'))

App.js

import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'

import Main from './main'
import * as projectActions from './actions/project'

const mapStateToProps = (state) => {
    return {
        project: state.project
    }
}

const mapDispatchToProps = (dispatch) => {
    return bindActionCreators({
        ...projectActions
    }, dispatch)
}

const App = connect(mapStateToProps,
    mapDispatchToProps)(Main)

export default App

main.js

import React from 'react'
import {
    BrowserRouter as Router,
    Route,
    Link
} from 'react-router-dom'

import {
    combineReducers,
    createStore,
    compose,
    applyMiddleware
} from 'redux'
import {
    ConnectedRouter,
    routerReducer,
    routerMiddleware
} from 'react-router-redux'

import {
    history,
    store
} from './store'

const Home = ({ match }) => (
    <div>Home</div>
)

const Tacos = ({ match }) => (
    <div>
        Tacos to order: 
        <Link to={`${match.url}/plain`}>Plain</Link>
        <Link to={`${match.url}/cheese`}>Cheese</Link>
        <Link to={`${match.url}/chipotle`}>Chipotle</Link>
        <div>
            <Route path={`${match.url}/:kind`} component={ Taco } />
        </div>
    </div>
)

const Taco = ({ match }) => (
    <div>You ordered {match.params.kind}</div>
)

const Main = (props) => (
    <ConnectedRouter history={ history }>
        <div>
            <Link to="/">Home</Link>
            |
            <Link to="/tacos">Tacos</Link>
            <div>
                <Route path="/" component={ Home } {...props}/>
                <Route path="/tacos" component={ Tacos } {...props}/>
            </div>
        </div>
    </ConnectedRouter>
)


export default Main

store.js

import createHistory from 'history/createHashHistory'
import {
    createStore,
    compose,
    applyMiddleware
} from 'redux'
import {
    routerMiddleware
} from 'react-router-redux'

import rootReducer from './reducers/index'
import { project } from './data'

const initialState = {
    project
}

export const history = createHistory()

export const store = createStore(rootReducer,
    initialState, compose(
    applyMiddleware(routerMiddleware(history))
))

I think those are the most important files for the setup. My question is, how do I access the props.newProject() function that I have in my actions from inside my Taco component? Using the React developer tool I can see that my Router has access to the props.newProject() but it's not present at the Taco level.

React dev tool

Should I use {...props} to pass the props to the Taco component or is there a smarter way?

I've used https://github.com/ReactTraining/react-router/tree/master/packages/react-router-redux as well as https://reacttraining.com/react-router/web/example/preventing-transitions as a reference.

1
if you want to use an action in a component, that's basically what connect is for. You are doing it already for App, you need to do the same for the Taco component if you wish to use the actions from that component as well. - Mario F
@MarioF how would that look? A connect()(Taco) and so forth for each component where I'd like to have access? That seams like a lot of extra work - kristian nissen
I mean you can either connect the component and get the properties you want from the state, or connect a parent component and pass the info to the children as props - Mario F

1 Answers

0
votes

One way would be to connect your components (like Taco) to the redux store individually (using connect), and then use mapStateToProps and mapDispatchToProps to only expose the relevant state and the relevant functions (like a function calling dispatch(someNewAction()) to the component.

So you would have a <TacoContainer /> component (connected to the redux store), and that would be the component you specify in your route.

That way the component itself knows how it should interact with the store. Then it becomes easier to use the component as a independent thing, because it already knows all (or most of) the tricky details, so no need to pass it lots of props and dispatch methods every time you use it. (You could still, if needed, pass it additional props from the outside though.)