Yashua Yashua - 3 months ago 22
React JSX Question

Organizing React app in component/container

I am working with React Redux Starter Kit and am trying to organize my code in component/container and struggling a bit with finding the right process. I realize it's a bit if a loose line but Id like some input on how to better organize things.

Currently I have 3 files - CheckoutForm (a redux form), CheckoutView (a simple page that has the form), and CheckoutContainer which right now does nearly nothing. Following the advice from reading about component/container separation it seems that the CheckoutView should be the same but that I should perhaps pull the submit function out of it and put that in the CheckoutContainer? How would I best rewire this code:

CheckoutContainer.js

import Checkout from '../components/CheckoutView'

export default Checkout


CheckoutView.js

import React from 'react'
import classes from './CheckoutView.scss'
import CheckoutForm from '../forms/CheckoutForm'

const submit = require('../modules/submit').default

export const CheckoutView = () => (
<div>
<h4 className={classes.header}>Checkout</h4>
<CheckoutForm onSubmit={submit}/>
</div>
)

export default CheckoutView


CheckoutForm.js

import { Field, reduxForm } from 'redux-form'

const renderField = ({ input, label, type, meta: { touched, error } }) => (
<div>
<label>{label}</label>
<div>
<input {...input} placeholder={label} type={type}/>
{touched && error && <span>{error}</span>}
</div>
</div>
)

const CheckoutForm = (props) => {
const { error, handleSubmit, pristine, reset, submitting } = props
return (
<form onSubmit={handleSubmit}>
<Field name="username" type="text" component={renderField} label="Username"/>
<Field name="password" type="password" component={renderField} label="Password"/>
{error && <strong>{error}</strong>}
<div>
<button type="submit" disabled={submitting}>Log In</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>Clear Values</button>
</div>
</form>
)
}

export default reduxForm({
form: 'checkoutForm'
})(CheckoutForm)

Answer

The main purpose of the container is to digest the information the component needs to know from the store and pass it to it, and also to provide callbacks as props that will handle the dispatching of actions in the container, so the component only has to pass the parameters it knows, and that's it. This way your component knows and does exactly what it needs, and nothing else, and it's not even aware of Redux at all.

Looking at your code, you got it right

I should perhaps pull the submit function out of it and put that in the CheckoutContainer

That's exactly what you should do, as it is the only thing the component does it should not care about.

In your container

import { connect } from 'react-redux';
import Checkout from '../components/CheckoutView';

const submit = require('../modules/submit').default

const mapStateToProps = state => {
    return { };
};

const mapDispatchToProps = dispatch => {
    return { onSubmit: submit };
};

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

And in the View:

import React from 'react'
import classes from './CheckoutView.scss'
import CheckoutForm from '../forms/CheckoutForm'

export const CheckoutView = ({ onSubmit }) => (
  <div>
    <h4 className={classes.header}>Checkout</h4>
    <CheckoutForm onSubmit={onSubmit}/>
  </div>
)

export default CheckoutView

As your application scales, you'll be ready to pass any information from the state to the component in mapStateToProps and additional callbacks in mapDispatchToProps.

Comments