2

What's the best practice for populating a select/dropdown from state?

I'm populated a redux-form like this...

import React from 'react';
import { connect } from 'react-redux';  
import { Field, reduxForm } from 'redux-form';  
import FormItem from '../FormItem.js';
import FormFooter from '../../components/FormFooter.js';
import Button from '../../components/Button.js';

let UserForm = props => {

  const { handleSubmit, onSubmit } = props;

    return (
    <form onSubmit={handleSubmit(onSubmit)}>

            <FormItem
                label = { <label htmlFor="firstName">First Name</label> }
                field = { <Field name="firstName" type="text" placeholder="First name" component="input" className="w-full"/>} 
            />

            <FormItem
                label = { <label htmlFor="lastName">Last Name</label> }
                field = { <Field name="lastName" type="text" placeholder="Last name" component="input" className="w-full"/> }
            />

            <FormFooter
                left={ <Button href="/users" icon="fa-ban" text="Cancel" /> }
                right={ <button type="submit">Save</button> }
            />

        </form>
    )
}

UserForm = reduxForm({
  form: 'userForm'
})(UserForm)

function mapStateToProps(state) {  
  return { initialValues: state.user.data }
}

UserForm = connect(mapStateToProps
)(UserForm)

export default UserForm

Here's the file that includes that form and gets the data:

import React from 'react';
import { connect } from 'react-redux';  
import PageHeaderBar from '../../components/PageHeaderBar.js';
import PageWrapper from '../PageWrapper.js';
import ContentWrapper from '../ContentWrapper.js';
import { loadUser, updateUser } from '../../actions/users';
import UserAccountForm from './UserAccountForm';
import { Values } from "redux-form-website-template";

class UserAccount extends React.Component {

  constructor(props) {
    super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
  }

  componentDidMount() {
        this.props.loadUser(localStorage.getItem('userId'));
  }

  handleSubmit(formProps) {
    this.props.updateUser(formProps);
  }

  render() {

    return (

      <PageWrapper>

        <PageHeaderBar title="User profile" />

        <ContentWrapper>
                    <UserAccountForm onSubmit={this.handleSubmit} />
                    <Values form="userForm" />
        </ContentWrapper>

      </PageWrapper>
    );
  }
}

export default connect(null, { loadUser, updateUser })(UserAccount);  

Root reducer:

import { combineReducers } from 'redux';  
import { reducer as formReducer } from 'redux-form';  
import authReducer from './auth_reducer';
import userReducer from './user_reducer';
import categoryReducer from './user_reducer';

const rootReducer = combineReducers({  
  auth: authReducer,
  form: formReducer,
  user: userReducer.
  category: categoryReducer
});

export default rootReducer; 

User reducer:

import { LOAD_USER_SUCCESS, LOAD_USERS_SUCCESS } from '../actions/types';

const INITIAL_STATE = { data: {} }

export default function (state = {}, action) {  
  switch(action.type) {
    case LOAD_USER_SUCCESS:
      return { ...state, data: action.data };
    case LOAD_USERS_SUCCESS:
      console.log('LOAD_USER_SUCCESS');
      return { ...state, data: action.data };
    default:
      return state;
  }
}

Now I want to add a select to the form above with the following component, and populate it's values from state.category.data. Here's what I have so far...

import React from 'react';
import { connect } from 'react-redux';  
import { loadCategories } from '../../actions/categories';
import { Field, reduxForm } from 'redux-form';  
import FormItem from '../FormItem.js';
import VirtualizedSelect from 'react-virtualized-select'
import 'react-datepicker/dist/react-datepicker.css';

export const renderSelect = (field) => (
  <VirtualizedSelect
    onChange={field.input.onChange}
    optionHeight={35}
    value={field.input.value}
  />
);

class CategorySelects extends React.Component {

  constructor(props) {
    super(props);
    console.log( 'props' );
    console.log( props.data );
  }

  render() {
    return (
      <FormItem
        label = { <label htmlFor="type">Category</label> }
        field = { <Field name="type" component={renderSelect} onChange={this.handleTypeChange} /> }
      />
    );
  }
}

export default CategorySelects

And I add this to the the form with:

<CategorySelects name="categories" />

What I'm not sure about is how to populate that select. Right now I just set initialValues on the UserForm with state.user.data. Do I need to merge in the state.category.data as well, or am I going about this the wrong way? Thanks!

1 Answer 1

1

I might be misunderstanding some of your code, but I think your problem is the hard-coded name in CategorySelects

<Field name="type" component={renderSelect} onChange={this.handleTypeChange} />

Since you are passing in the name when you add the form via

Then your Field on CategorySelects should look like this

<Field name={props.name} component={renderSelect} onChange={this.handleTypeChange}/>

Assuming your initialValues looks like

{firstName: "Bob", lastName: "Smith", categories: [10, 20, 30] }

That would make sure your options are selected, but I don't how you're pushing your options into the component.

If populating your options what you're trying to figure out, then yes, you need to push state.category.data into your component, but I wouldn't do it via redux-form, I would just pass that data as a prop to CategorySelects which would in turn pass it to VirtualizedSelect via your renderSelect function.

If you user data looks like this, then ignore the whole first part of my answer:

{firstName: "Bob", lastName: "Smith", type: 10 }

The long and short is that redux-form will help you manage the value of your forms, but options are something you would take care of in the same manner as using non-redux forms.

Here is the example from the redux-form website

<Field name="favoriteColor" component="select">
    <option />
    <option value="#ff0000">Red</option>
    <option value="#00ff00">Green</option>
    <option value="#0000ff">Blue</option>
</Field>

Is if your initial value object was {favoriteColor: "#00ff00"}, then Green would be selected when the component rendered.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.