Home > Net >  Can't access redux actions from props when working with react router
Can't access redux actions from props when working with react router

Time:01-29

I'm pretty new to react and redux and I have been having a problem accessing my redux actions from the props when used in conjunction with react router. I have tried lots of configurations for formatting but no matter what I try the props only have the react router functions i.e. history, match and location. I am using connected-react-router but it does not seems to be doing anything. I have been able to access the redux actions from my nav menu components so I don't think anything is wrong there.

Here is a sample of the latest configuration I tried:

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

const ConnectedApp = connect(
    mapStateToProps,
    { signOut, signIn }
)(App);

ReactDOM.render(
    <Provider store={store}>
        <ConnectedRouter basename={baseUrl} history={history}>
            <ConnectedApp />
        </ConnectedRouter>
    </Provider>,
  rootElement);

and here is inside App:

class App extends Component {
    static displayName = App.name;


  render () {
    return (
        <Layout>
            <Route exact path='/' component={(props) =><Home {...props}/>} />
            <Route exact path='/LogInExisting' component={(props) => <LogInExisting {...props} />} />
            <Route exact path='/LogInCreate' component={(props) => <LogInCreate {...props} />} />
      </Layout>
    );
  }
}

And here is whats trying to access the signIn action:

const LogInExisting = (props) => {
    const history = useHistory();

    const handleSignIn = async (e) => {
        e.preventDefault()

        var data = {
            UserName: document.getElementById('login').value,
            Password: document.getElementById('password').value
        }

        var response = await fetch('LogInExistingUser', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(data)
        });

        var respData = await response.json();
        if (!respData.success) {
            //TODO: Error handling
        } else {
            props.signIn();
            history.push('/')
        }
    }

I feel like I am missing something obvious but I really could use some help.

CodePudding user response:

You are passing the route props (history, location, and match) when using the Route component's component prop function.

<Route
  exact
  path='/LogInExisting'
  component={(props) => <LogInExisting {...props} />}
/>

Missing is the passing through of the props that were passed to App.

<Route
  exact
  path='/LogInExisting'
  component={(routeProps) => <LogInExisting {...routeProps} {...this.props} />}
/>

You don't want to use an anonymous function on the component prop as this will remount the routed component each time App renders. Instead, use the render prop function, it's meant for this use case. See Route render methods for more in-depth explanation.

<Route
  exact
  path='/LogInExisting'
  render={(routeProps) => <LogInExisting {...routeProps} {...this.props} />}
/>

This being said though, you are using Redux, which is built using the React Context API, which solves the issue of "props drilling". You shouldn't be passing your redux state and actions down as props like this. Wrap your routed components in the connect HOC locally.

<Route exact path='/LogInExisting' component={LogInExisting} />

LogInExisting

const mapStateToProps = (state) => ({
  isSignedIn: state.auth.isSignedIn,
});

const mapDispatchToProps = { signOut, signIn };

export default connect(mapStateToProps, mapDispatchToProps)(LogInExisting);

Since LogInExisting is a function component, you can use the useDispatch and useSelector hooks instead of the connect HOC.

import { useDispatch, useSelector } from 'react-redux';
import { signIn } from '../path/to/actions';

const LogInExisting = (props) => {
  const dispatch = useDispatch();
  const isSignedIn = useSelector(state => state.auth.isSignedIn);

  const history = useHistory();

  const handleSignIn = async (e) => {
    e.preventDefault();

    ...

    if (!respData.success) {
      //TODO: Error handling
    } else {
      dispatch(signIn());
      history.push('/');
    }
}
  •  Tags:  
  • Related