0

I have a stateless dropdown list component in my react/redux/es6 application. I store its selected value in state so the previously selected value is remembered. Every time the user navigates to this page, however, the drop down list's value is not initially selected correctly. Any action that triggers a re-rendering of the view sets the value correctly.

I can confirm that the value is passed to the drop down list component correctly every time, including the first time the view is rendered.

const DropDownList = ({name, label, options, selectedValue, error, onChange}) => {
let wrapperClass = 'form-group';
if (error && error.length > 0) {
  wrapperClass += " " + 'has-error';
}

let optionsMarkup =  [];

for(let i=0;i<options.length;i++){
  optionsMarkup.push(<option key={options[i]}>{options[i]}</option>);
}

return (
  <div className={wrapperClass}>
    <label htmlFor={name} className="control-label">{label}</label>
    <select name={name} title="Please select" data-live-search="true" className="form-control" onChange={onChange} value={selectedValue}>
      {optionsMarkup}
    </select>
  </div>
 );
};

It seems pretty straight forward. There is a stateless component which passes values to this one:

const SearchForm = ({name, onSubmit, topText, onSearchTermChange, onCategoryChange, submitting, errors, searchResults, searchTerm, searchCategory}) => {

const reasons = ['Select a Reason for Search',
        'A',
        'B',
        'C',
        'D'];

return (
  <section>
    <ErrorSummary errors={errors} />
    <p>{topText}</p>
    <form role="form">
      <TextInput
        name="searchTerms"
        label="Search Terms"
        placeholder="Example search here"
        type="text"
        error={errors.title}
        onChange={onSearchTermChange}
        value={searchTerm} />

      <DropDownList
        name={name}
        label="Seaarch Reason"
        options ={reasons}
        selectedValue={searchCategory}
        onChange={onCategoryChange} />

      <div className="col-md-2 col-xs-12">
        <button type="submit" className="btn btn-primary col-md-12" onClick={onSubmit} disabled={submitting}>{submitting ? "Searching" : "Search"}</button>
      </div>
    </form>
  </section>
  );
};

And there is a stateful component which contains two SearchForms, passing the event handlers:

render() {
  return(
    <section>
      <div className="tab-content">
        <div className="col-md-12 tab-pane active" role="tabpanel" id="searchPage">
          <div className="container">
            <div className="row">
              <div className="col-md-12 well center-block">
                <nav role="navigation">
                  <ul className="nav nav-pills nav-justified">
                    <li role="presentation" className={this.props.searchView == "searchOne" ? "active" : ""}><a href="#searchOne" data-toggle="tab" onClick={this.searchViewChanged.bind(null, "searchOne")}>search One</a></li>
                  <li role="presentation" className={this.props.searchView == "searchTwo" ? "active" : ""}><a href="#searchTwo" data-toggle="tab" onClick={this.searchViewChanged.bind(null, "searchTwo")}>search Two</a></li>
                </ul>
              </nav>
              <div className="tab-content">
              <div className={this.props.searchView == "searchOne" ? "col-md-12 well tab-pane active" : "col-md-12 well tab-pane"} role="tabpanel" id="searchOne">
                <SearchForm
                  name="searchOne"
                  onSubmit={this.searchOne}
                  topText="search one text"
                  submitting={this.state.submitting}
                  errors={this.state.searchOneErrors}
                  onSearchTermChange={this.searchOneTermChanged}
                  onCategoryChange={this.searchOneCategoryChanged}
                  searchResults={this.props.searchOneSearchResults}
                  searchTerm={this.state.searchOneTerm}
                  searchCategory={this.state.searchOneCategory} />
              </div>
              <div className={this.props.searchView == "searchTwo" ? "col-md-12 well tab-pane active" : "col-md-12 well tab-pane"} role="tabpanel" id="searchTwo">
                <SearchForm
                  name="searchTwo"
                  onSubmit={this.searchTwo}
                  topText="search Two text"
                  submitting={this.state.submitting}
                  errors={this.state.searchTwoSearchErrors}
                  onSearchTermChange={this.searchTwoSearchTermChanged}
                  onCategoryChange={this.searchTwoCategoryChanged}
                  searchTerm={this.state.searchTwoTerm}
                  searchCategory={this.state.searchTwoCategory} />
              </div>
            </div>
          </div>
        </div>
        ....
        ....
      </div>
    </div>
  </div>
  </section>

I am out of ideas why this is happening. Any thoughts?

2 Answers 2

1

I don't believe how simple this was. I just had to add "value" to option and all is set. Not sure why it was working on re-render in absence of value attribute. So, the for loop in DropdownList component should look like this:

for(let i=0;i<options.length;i++){
  optionsMarkup.push(<option key={options[i]} value={options[i]}>{options[i]}</option>);
}
Sign up to request clarification or add additional context in comments.

Comments

0

Maybe its connected with the way you're passing props?

searchTerm={this.state.searchTwoTerm}

Why are you using this.state directly. Since you're using redux better way to do that is to invoke mapStateToProps and connect component (and then use this.props) Docs: http://redux.js.org/docs/basics/UsageWithReact.html

But its just a thought, dont know if its the issue.

Second thought is that you might not set default value of searchTwoTerm in the reducer so if you refresh the page, persisted state is gone and default value goes in. (but you wrote that even by the first time component is rendered, value is good.. so its also may not be the case).

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.