React-redux: Update react-redux docs for forwardRef

Created on 12 Dec 2018  路  12Comments  路  Source: reduxjs/react-redux

Re this issue: https://github.com/reduxjs/react-redux/issues/1118

After rereading the react redux docs, the reason I thought withRef could only be used with connectAdvanced is because withRef only appears under [connectOptions] for connectAdvanced, and not regular connect. Had I read more carefully about connect I would've seen that it's a wrapper around connectAdvanced but I don't think it's obvious that withRef/forwardRef can be passed to just connect as it's not under [options]

Most helpful comment

A working solution with a functional component and connect :

const YourConnectedFC: FC = forwardRef((props, ref) => {
    <Input ref={ref} />
});

export default connect(
    null, // mapStateToProps
    null, // mapDispatchToProps
    null, // mergeProps
    { forwardRef: true }, // options
)(YourConnectedFC);

All 12 comments

Still a bit vague especially if I am approaching react-redux for the first time and trying to upgrade the codebase of an old project, for instance. Where do I need to use it and how can I pass it?

Does this work?

    export default connect(
        mapStateToProps,
        mapDispatchToProps,
        options: {
            forwardRef: true,
        },
    )(MyComponent);

Or is it something like this?

    export default connect(
        mapStateToProps,
        mapDispatchToProps,
        forwardRef: true,
    )(MyComponent);

Or even this?

    export default connect(
        mapStateToProps,
        mapDispatchToProps,
        { forwardRef: true },
    )(MyComponent);

@luigimannoni : please look at the API docs more carefully:

https://react-redux.js.org/api/connect

The signature is:

function connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)

Well, I have tried and it does not work well at all:

import React, { forwardRef } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import {
  NavigationContainer as NavigationContainerDefault,
} from '@react-navigation/native';

function NavigationContainer({ theme, ...rest }) {
  return (
    <NavigationContainerDefault theme={theme} {...rest} />
  );
}

NavigationContainer.propTypes = {
  /** @ignore */
  theme: PropTypes.object.isRequired,
  /** Settings allow you to use other icons than MaterialCommunityIcons */
  settings: PropTypes.object,
};

NavigationContainer.defaultProps = {
  settings: undefined,
};

const mapStateToProps = (state) => ({
  theme: state.layout.themes[state.preferences.colorScheme],
});


const connectAndForwardRef = (
  mapStateToProps = null,
  mapDispatchToProps = null,
  mergeProps = null,
  options = {},
) => (component) => connect(
  mapStateToProps,
  mapDispatchToProps,
  mergeProps,
  {
    ...options,
    forwardRef: true,
  },
)(forwardRef(component));

const ConnectedNavigationContainer = connectAndForwardRef(mapStateToProps)(NavigationContainer);

export default ConnectedNavigationContainer;

This result in :

import React, { forwardRef } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import {
  NavigationContainer as NavigationContainerDefault,
} from '@react-navigation/native';

function NavigationContainer({ theme, ...rest }) {
  return (
    <NavigationContainerDefault theme={theme} {...rest} />
  );
}

NavigationContainer.propTypes = {
  /** @ignore */
  theme: PropTypes.object.isRequired,
  /** Settings allow you to use other icons than MaterialCommunityIcons */
  settings: PropTypes.object,
};

NavigationContainer.defaultProps = {
  settings: undefined,
};

const mapStateToProps = (state) => ({
  theme: state.layout.themes[state.preferences.colorScheme],
});

const connectAndForwardRef = (
  mapStateToProps = null,
  mapDispatchToProps = null,
  mergeProps = null,
  options = {},
) => (component) => connect(
  mapStateToProps,
  mapDispatchToProps,
  mergeProps,
  {
    ...options,
    forwardRef: true,
  },
)(forwardRef(component));

const ConnectedNavigationContainer = connectAndForwardRef(mapStateToProps)(NavigationContainer);

export default ConnectedNavigationContainer;
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

@kopax you can't give a ref to a function component, you need to export it as a class

I solved it with a function component..you need to stack useRef in connect and with the function.

You should avoid class @dereknelson

I solved it with a function component..you need to stack useRef in connect and with the function.

You should avoid class @dereknelson

Hi @kopax ! Do you have any exemple please ?

By stack I mean wrap your component with forwardRef as stated in reactjs documentation and also use the connect option with forwardRef true.

Try with a simple component. Not all components from 3rd party libraries handle it correctly. Try with one of your own as I said and it will work

A working solution with a functional component and connect :

const YourConnectedFC: FC = forwardRef((props, ref) => {
    <Input ref={ref} />
});

export default connect(
    null, // mapStateToProps
    null, // mapDispatchToProps
    null, // mergeProps
    { forwardRef: true }, // options
)(YourConnectedFC);

Exactly, bravo:)

A working solution with a functional component and connect

And how would this work with class components?

Just in case anyone is wondering with the @adrienlamotte example, you should still be able to pass along mapStateToProps and mapDispatchToProps as normal

const YourConnectedFC: FC = forwardRef((props, ref) => {
    <Input ref={ref} />
});

export default connect(
    mapStateToProps // pass these props to YourConnectedFC
    mapDispatchToProps // pass these dispatch props to YourConnectedFC
    null, // mergeProps
    { forwardRef: true }, // options
)(YourConnectedFC);
Was this page helpful?
0 / 5 - 0 ratings