Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I can't understand why components with 'connect()' are stateful in react

My question is just same as the title.

Let's say I wrote the following code.

class TODOList extends Component {  
  render() {
    const {todos, onClick} = this.props;
    return (
      <ul>
            {todos.map(todo =>
                <Todo 
                    key={todo.id}
                    onClick={onClick}
                    {...todo}
                />
             )}
      </ul>
    );
  }
}


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


const mapDispatchToProps = (dispatch) => {  
    return {
        onClick(data){
          dispatch(complete(data)) 
        }
    }
}


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

Now, after the last line, this code will export the TODOList component with the state as props. It's not that it contains state, but just received state and will have them as 'props', just like the method name 'mapStateToProps' explains.

In the medium post(https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0) written by Dan Abramov, container component handles data as state, and presentational property do as props. Isn't it a presentational component that deals with data as props? I'm stuck with the idea that the right container should be one like below.

class CommentList extends React.Component {
  this.state = { comments: [] };

  componentDidMount() {
    fetchSomeComments(comments =>
      this.setState({ comments: comments }));
  }
  render() {
    return (
      <ul>
        {this.state.comments.map(c => (
          <li>{c.body}—{c.author}</li>
        ))}
      </ul>
    );
  }
}

I'm not sure why react-redux named the API 'mapStateToProps', when I tried to make 'stateful'(not handling data by property) container component

like image 650
Rhee Avatar asked Dec 16 '18 12:12

Rhee


1 Answers

First of all these guidelines are not part of the bible
you should write code that is easy to reason about for YOU and your TEAM.

I think you are missing something, A redux Container is different than a react Container.
I mean, connect will create the container for you, it doesn't mean the wraped component is a Container.

Basically you can export both versions from the same file, the Container (connected version) and the presentation version (the none connected one).

Another thing that usually throw people off, is the name of the function and argument of mapStateToProps.
I prefer the name mapStoreToProps as in

map the redux store to the component's props.

the name state can be confusing when we are in the context of react.

Edit
As a followup to your comment:

I totally didn't know these two are actually different. Could you please tell me about more details

They are different in the way that connect is creating a "Container" for you.

connect is a High Order Component that creates the Container Component for us with all the subscription logic + functions to pass portions of the store and action-creators to its children as props (mapStateToProps & mapDispatchToProps).

A "normal" Container is usually refers to a component that you write by hand, its often doesn't deal with how things should look but instead deal with certain logic of the app.

As for the other comments like

The connect HoC of react-redux just injects the properties you can request into your component. It returns a new component that is wrapped around your component so that it can update your component whenever the state you're interested in the redux store is modified

As i mentioned above, this is partially true. It's not just injecting the properties into our component, its subscribing to the store, grabbing it from the Provider (via context) and its doing all these with optimizations in mind, so we won't have to do it by ourselves.

I'm not sure how mapStateToProps can confuse someone. We are talking about a state management library

I've seen some devs that misunderstood this because react has a state and redux has a store (at least that's how it was called in most of the tutorials and documentations).
this can be confusing to some people that are new to either react or redux.

Edit 2

It was a bit confusing due to the sentence 'it doesn't mean the wraped component is a Container.' Why is the wrapped component not a container? Isn't a component created by connect also a container?

I mean that the wrapped component that you wrote doesn't have to be a Container.
You can connect a "Presentation" component:

const Link = ({ active, children, onClick }) => {
  if (active) {
    return <span>{children}</span>
  }

  return (
    <a
      href=""
      onClick={e => {
        e.preventDefault()
        onClick()
      }}
    >
      {children}
    </a>
  )
}

// ...
export default connect(mapState, mapDispatch)(Link)
like image 179
Sagiv b.g Avatar answered Oct 12 '22 14:10

Sagiv b.g