Why does Meteors createContainer set props instead of state?


#1

I have a list of messages inside a user document in the profile object, which are found at user.profile.siteMessages.

I am simply wanting to render the messages to my <ul>. I noticed that according to the docs, you use the following to wrap your component with a container:

Messages.propTypes = {
  currentUser: PropTypes.object,
};

export default createContainer(() => {

  return {
    currentUser: Meteor.user(),
  };
}, Messages);

The values are then suppose to be accessed via this.props:

class Messages extends React.Component {

	constructor(props) {
		super(props);
		this.state = {
			messages: [],
		}
	}

	renderMessages() {
	
		console.log(Meteor.user())
		if (!this.props.currentUser) {
			return ""
		} else {
				let msgs = this.props.currentUser.profile.siteMessages.map((obj) => {
				return (
					<li key={obj.createdAt.toString()}>
						<div>{obj.text} </div>
					</li>
				);
			})
			return msgs;
		}
	}

	check() {
		console.log(Meteor.user())
	}

	render() {
		return (
			<div className="messages">
				<ul className="messages-list">
					{this.renderMessages()}
					<button onClick={this.check}></button>
				</ul>
			</div>
		);
	}
}

I have a few questions:

  1. Why is the value put into props instead of the components state?

  2. renderMessages seems to be called twice. The first time, the log statement at the start of the function prints undefined, presumably because Meteor.user() has not loaded. The second time it prints the object. Why is the function being run twice? Im assuming its because the previously mentioned prop is given a new value once the container loads it, but how does that cause the function to rerun?


#2

Whenever the props of a React component change, the render function re-runs. The container sets new props, so the component gets re-rendered.

Higher order components, as they are called, are definitely today’s best practice in React: https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750#.41qrqtlrc


#3

I suppose Im just confused on how createContainer works. With a ‘regular’ container component, you would wrap the child component that would receive the data but the parent component would render the container.

With createContainer, I’m passing in the Messages component and exporting it, but in the parent component that renders Messages, i’m still just rendering <Messages/> (well, the router is rendering it where this.props.children is in the parent).


#4

The name doesn’t matter - it’s just a variable name. You can call it MessagesContainer if you like.