connect method redux arguments - javascript

The following piece of syntax when dealing with redux's connect method is confusing me.
export default connect(
mapStateToProps,
mapDispatchToProps
)(TodoItem)
connect takes two arguments, mapStateToProps, mapDispatchToProps, which makes sense. The same as any function i.e.
function sum(a, b){
return a + b;
}
sum(2, 8);
However, what is confusing me is the the next argument, in the example I provided above (TodoItem). Can anyone explain what is happening here?

You need to export a component from your JSX. The connect function is a higher order function, meaning it returns a new function.
The new function that it returns is actually a higher order component. This means that it is a component that returns another component. In this case, it is the Provider component that wraps your component.
At this point:
connect(mapStateToProps, mapDispatchToProps)
you've not actually told the connect function which component to wrap.
connect(mapStateToProps, mapDispatchToProps)(TodoItem)
But here you've also told it which component to wrap.
Summary
So the first two functions you pass in as arguments tell it what the component needs. The last function argument tells it which component it is that needs them.

This is function currying.
In general, this is a function that returns a function.
In the connect the use case is to pass the component as an argument to the "second" inner function and that way it will have access for all 3 parameters.
One simple use case is when you want to pass extra parameter to onClick event.
var root = document.getElementById('root');
root.addEventListener('click', clicked('i Was clicked!!'));
function clicked(param){
return function(e){
// both parameters acceesible
console.log(param);
console.log(e.target.innerHTML);
}
}
<button id="root">Click me</button>
So behind the scene it invoked like this:
clicked('i was clicked!!')(event)

Related

In JavaScript, what is the point of defining a function with default parameters for some arguments before other arguments without default parameters?

I was reading the Redux documentation and something really confused me. Many, if not all, of the example reducer functions in the documentation have this kind of signature:
function visibilityFilter(state = 'SHOW_ALL', action) {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter
default:
return state
}
}
What is the point of providing a default state when the action is required anyway?
In that particular code sample, calling visibilityFilter without providing an action argument will result in a TypeError at the switch statement.
But in order to provide an action parameter, the state parameter must also be provided, and so the default value is overridden and useless. As far as I know, there is simply no way in the JavaScript syntax to call that visiblityFilter function while providing only the action parameter.
Is that just some funky/bad coding style in the world of Redux? What am I missing?
That's some pretty strange code, but there is one case where the default parameter could be used - if undefined is explicitly passed as the first parameter:
function visibilityFilter(state = 'SHOW_ALL', action) {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter
default:
return state
}
}
console.log(visibilityFilter(undefined, {}));
(not that I would recommend writing code that looks like this in most cases)
With Redux in particular, this sort of thing can arise "naturally" because the function is a reducer, used with createStore. If createStore is passed an initial state, it'll be passed along to the reducer as the reducer's first argument; otherwise, Redux's internals will explicitly call it with an undefined first argument.

Is there any reason React Redux Connect returns a function and not a component directly?

I am trying to understand more about higher order components and my understanding is the typical pattern is like this:
const HOC = (WrappedComponent) => {
...
return class extends React.Component {
render(){
<WrappedComponent {...this.props} />
}
}
}
Which you could call like this: HOC(CustomComponent)
However many popular libraries including react-redux instead return a function that in turn returns the component:
const connect = (mapStateToProps) => {
...
const storeToPass = mapStateToProps(store)
return function(WrappedComponent) {
return class extends React.Component {
render(){
<WrappedComponent {...this.props, ...storeToPass} />
}
}
}
}
which you would call like this: connect(mapState)(CustomComponent)
My question is why? Is there any reason for this or is it just a preference on pattern? Why couldn't you do this for the connect function?
const connect = (mapStateToProps, WrappedComponent) => {
...
const storeToPass = mapStateToProps(store)
return class extends React.Component {
render(){
<WrappedComponent {...this.props, ...storeToPass} />
}
}
}
And call it like this: Connect(MapState, CustomComponent)
Is there any difference?
For one thing, connect accepts (up to) four arguments: mapStateToProps, mapDispatchToProps, mergeProps and options. https://react-redux.js.org/api/connect#connect
Of course in theory the function signature could have been flipped to connect(Component, mapStateToProps, mapDispatchToProps, mergeProps, options).
However, the reason given from the documentation:
you may use the hoc to enable different components to get the same behavior
Their example is giving two different components login/logout actions:
// first call: returns a hoc that you can use to wrap any component
const connectUser = connect(
mapState,
mapDispatch
)
// second call: returns the wrapper component with mergedProps
// you may use the hoc to enable different components to get the same behavior
const ConnectedUserLogin = connectUser(Login)
const ConnectedUserProfile = connectUser(Profile)
https://react-redux.js.org/api/connect#connect-returns
A bit late, but in addition to #anthonygood's answer, there is another reason which has to do with using multple HOCs. See the react docs on HOCs. Briefly, instead of having to chain calls to HOCs you can compose them as shown in the code snippet below taken directly from REACT docs on HOCs.
// Instead of doing this...
const EnhancedComponent = withRouter(connect(commentSelector)(WrappedComponent))
// ... you can use a function composition utility
// compose(f, g, h) is the same as (...args) => f(g(h(...args)))
const enhance = compose(
// These are both single-argument HOCs
withRouter,
connect(commentSelector)
)
const EnhancedComponent = enhance(WrappedComponent)
The concept of HOC in react was introduced later after the redux library. And the function itself is known as a component in react. So, you know the deal; it's pretty complex to change everything that already is published. If it has to implement the way react hook is implemented then there would be blunder changes required by most of the softwares.
Connect returns a function because this function needs to be very flexible which in turns means it has to take many customization options as arguments. Surely CustomComponent could be just another argument passed to Connect so that you would have HOC(CustomComponent, option1, ...optionN).
Another and neater option taken by Redux creators was to pass all the customization options as arguments to Connect separately and in return get another function, already customized. This customized function then takes CustomComponent as the only argument.

Why are stateless functions not supposed to have methods?

I have read in multiple places that stateless functions in React are not supposed to have inner functions. Why is it so, though it works?
const Foo = () => {
let bar = () => {
return <span>lorem ipsum</span>
}
return <div>{bar()}</div>
}
This works. But, why is this not supposed to be done?
N.B. This answer assumes that the use of the word "method" was incorrect, and that we are actually talking about an inner function, as in the example provided in the question.
A stateless component is defined as a function which returns something that can be rendered by React:
const MyStatelessComponent = function (props) {
// do whatever you want here
return something; // something must be render-able by React
}
To (re-)render the component, React calls the function, so it makes sense to perform expensive computations in advance and save their result outside of the function.
In your toy example, the function bar is declared once per render, and only used once. Let's assume that it was slightly more complicated and pass it a single parameter:
const Foo = () => {
let bar = text => {
return <span>{text}</span>
}
return <div>{bar("lorem ipsum")}</div>
}
By moving bar outside of the component, you don't need to create the function once per render, you just call the function that already exists:
const bar = text => {
return <span>{text}</span>
}
const Foo = () => {
return <div>{bar("lorem ipsum")}</div>
}
Now your component is ever-so-slightly more efficient, since is does less work every time it is called.
Also note that bar is almost the same as a stateless component now, and could easily be turned into one by making the function take a props object rather than a single string argument.
But the bottom line is that you can do whatever you want inside the stateless component. It just is worth bearing in mind that it will happen once per (re-)render.
While still valid code, as far as react is concerned, the above example is not a stateless component.
A stateless component is basically a shortcut to the render method of a stateful component (without the same life-cycle) and should "ideally" only return data, not define methods or actually manipulate or create additional data or functionality. With a stateful component, ideally, you do not define methods within the render method so none should be added in a stateless component.
By defining a method, function, or parameter inside of a stateless component but outside of the render method, you are essentially saying that there is a possibility of manipulation within the stateless component, which defeats the purpose.
Mind you, it's still valid code...but just not "react" ideal.
The function Foo is basically the render method of the React component. Therefore, it will be called everytime the component needs to be rendered. By declaring a local function inside it, it will create a new function everytime the component re-renders, which is bad.
Either declare the function outside or implement a stateful component instead.

Connect actions to functions

Recently I've been using react classes and using mapStateToProps and the react-redux connect, i've been able to use actions within my classes because of this, however now I'm trying to write functions that don't belong to a class like the following
import { some_imported_action } from '../actions/my_actions';
export function f() {
some_imported_action();
}
But I'm having trouble trying to get the function to run the action imported, I assume the problem is trying to use the react-redux connect with a function instead of a class. When I run the code above nothing happens, no errors but the action doesn't execute.
I've tried importing prop-types and making the function required with
some_imported_action: PropTypes.func.isRequired
The errors I get from trying to run it are things to do with either 'this', or 'props' is undefined in the line.
this.props.some_imported_action();
I think it might not even be possible without a class, any ideas?
Thanks
When your f() function is called nothing happens with Redux because the action creator (some_imported_action) is not connected to your store.
Redux actions needs to be dispatched using the store.dispatch function in order to be handled by reducers.
The connect function from react-redux receive as second argument a mapDispatchToProps object or function:
[mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function):
If an object is passed, each function inside it is assumed to be a
Redux action creator. An object with the same function names, but with
every action creator wrapped into a dispatch call so they may be
invoked directly, will be merged into the component’s props.
If a function is passed, it will be given dispatch as the first parameter. It’s up to you to return an object that somehow uses dispatch to bind action creators in your own way.
Example passing a callback prop called someAction binded with store dispatch:
import { connect } from 'react-redux';
const someAction = () => ({ type: 'SOME_ACTION' });
function MyComponent({ someAction }) {
return <div onClick={someAction}>...</div>;
}
export default connect(null, { someAction })(MyComponent);
Read more info related to React-Redux connect

How do I disallow use of a required parameter in a ES7 function definition?

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
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 => {
…
});
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].

Categories

Resources