0

Question

I am writing a ES7 function that will be called by an API which defines the parameter order:

mapStateToProps(state, [ownProps]): stateProps

I need to use ownProps but not state. Is it possible to write the function definition so that the first parameter is either not specified or any attempt to read it or write it will result in an error ("fail fast")?


This doesn't work

This looks appealing, but of course _ is a valid variable name...:

function myMapStateToProps(_, ownProps) {
  // ...
}

Some more context

My question is really the mirror of Skipping optional function parameters in JavaScript.

The context to my question is that I'm writing a pair of React components which implement a button that does something when it's clicked.

The inner component specifies the layout, including the button text, and the outer component makes the modal visible and is composed with the inner component using react-redux's connect function:

function MyButton({ handleOpen }) {
  return (
    <Button onClick={handleOpen} className={s['cta-button']}>
      Button text that I want to configure
    </Button>
  );
}

const mapStateToProps = () => {
  return {};
};

const mapDispatchToProps = (dispatch) => {
  return {
    handleOpen: () => dispatch(doSomeStuff()),
  };
};

const MyButtonContainer = connect(
  mapStateToProps,
  mapDispatchToProps,
)(MyButton);

export default MyButtonContainer;

Usage is:

<MyButtonContainer />

What I want to do is make the text displayed on the button configurable via a property passed to MyButtonContainer:

<MyButtonContainer text="Click me" />

By using the second parameter of the function used to map state to props (ownProps) I can access the text property, but I still don't need anything from the state so for clarity and to reduce the chance of causing bugs I want to write the mapStateToProps function so that the first parameter is unusable.

I am transpiling from ES7 so any standard ES is fine. If there are proposed extensions I might also be able to use those (thanks webpack).

Alternately, if there's a better way of doing this in React I'd be open to that solution too.


Why not put the button text in the redux store?

This is a technical option. I don't like it for several reasons: - The button text is a property of the inner component, if I wasn't using a HOC to wrap it and provide the button functionality I'd just specify it directly as a property - Putting it in the redux store is a lot of coding overhead - writing reducers, store initialisers, action creators, there must be a better and easier way! - I want to display multiple buttons on the same rendered page, each with different text - no matter what I'm going to have to specify properties on the container class, having it be the text to display just seems cleanest

cfogelberg
  • 1,288
  • 14
  • 24
  • "But of course `_` is a valid variable name". Isn't that a good thing? Just use that. – Oriol Jan 12 '17 at 20:34
  • @Oriol I want to ensure that the first parameter passed to my mapStateToProps method is never used and that the person reading the code knows this just from looking at the function signature, so using any valid variable definition is a bad thing. In a perfect world or if I was a perfect dev I'd rewrite the API to pass an options object and then I could destructure it in my method. But it's not a perfect world and I'm not a perfect dev – cfogelberg Jan 12 '17 at 21:25

2 Answers2

1

If you want to disallow access to a variable, just shadow it with a more local one, and don't initialize it.

function func1(_, arg) {{
  return 'This works: ' + arg;
  let _;
}}
function func2(_, arg) {{
  return 'This throws: ' + _; // ReferenceError
  let _; // Prevents access to _
}}
console.log(func1(1,2));
console.log(func2(3,4));

The argument will still be accessible via arguments[0].

Oriol
  • 225,583
  • 46
  • 371
  • 457
1

Using _ should be fine. It's intention is clear, and it shouldn't be used by accident by sensible developers.


You can use a higher-order function that drops the first argument:

function noState(fn) {
    return (state, ...rest) => fn(...rest); // I'm assuming the `this` context doesn't matter
}

myMapStateToProps = noState(ownProps => {
    …
});
Bergi
  • 513,640
  • 108
  • 821
  • 1,164