简体   繁体   中英

Warning: flattenChildren(…): Encountered two children

I have looked at this same issue but could not figure out where my error is.

My live search box works great but once you have removed your search query (word) the warning shows up in the react console:

Warning: flattenChildren(...): Encountered two children with the same key, .$1 . Child keys must be unique; when two children share a key, only the first child will be used.

This is my entire jsx file:

var SearchBox = React.createClass({
    doSearch:function(){
      // remove .getDOMNode() for newer version of reat-rails 1.4.x
      var query = (this.refs.searchInput.value).toLowerCase(); // this is the search text
      this.props.doSearch(query);
    },
    render:function(){
        return <input type="text" ref="searchInput" placeholder="Search title, country and city" value={this.props.query} onChange={this.doSearch}/>
    }
});

var DisplayTable = React.createClass({
    render:function(){
        //making the cards to display
        var cards=[];
        var default_url = "/assets/profile_avatar/thumb/missing.png";
        this.props.data.map(function(s) {
          cards.push(
            <a href={'/users/' + s.user.id + '/supports/' + s.id} key={s.id}>
              <div className="card">
                <div className="row">
                  <div className="small-5 large-6 columns">
                    <h5>{s.support_title}</h5>
                  </div>
                  <div className=" fi small-3 large-3 columns">
                    Reward: {s.reward_after_support}
                  </div>
                  <div className="small-4 large-3 columns talr">
                     {s.remote_support == 'on' ? 'Remote / Anywhere' : s.city + ', '+ s.country}
                  </div>
                  <hr />
                  <div className="cl">
                    <img className="profile-img" src={ s.profiles[0].avatar_file_name === null ? default_url : s.profiles[0].avatar_url}></img><span>{s.profiles[0].first_name}</span>
                  </div>
                  <div className="cr">
                    Applications: {s.interest_recieved} |
                    Posted: {moment(s.created_at).fromNow()}
                  </div>
                </div>
              </div>
            </a>
           )
        });
        //returning the card
        return(
          <div>
            {cards}
          </div>
        );
    }
});

var InstantBox = React.createClass({
    doSearch:function(queryText){
        //console.log(queryText)
        //get query result
        var queryResult=[];
        this.props.data.map(function(s){
          if(s.support_title.toLowerCase().indexOf(queryText)!=-1) {
            queryResult.push(s);
          }
          if (s.city != null) {
            if(s.city.toLowerCase().indexOf(queryText)!=-1) {
              queryResult.push(s);
            }
          }

          if (s.country != null) {
            if(s.country.toLowerCase().indexOf(queryText)!=-1) {
              queryResult.push(s);
            }
          }
        });

        this.setState({
            query:queryText,
            filteredData: queryResult
        })
    },
    getInitialState:function(){
        return{
            query:'',
            filteredData: this.props.data
        }
    },
    render:function(){
        return (
            <div className="InstantBox">
              <div className="search">
                <SearchBox query={this.state.query} doSearch={this.doSearch}/>
              </div>
                <DisplayTable data={this.state.filteredData}/>
            </div>
        );
    }
});

I really dont see an issue. Am I missing something?

The quirk in your code is that the indexOf()!=-1 only works if the passed string is not empty. So

'Milan'.indexOf('M') // = 0
'Milan'.indexOf('Q') // = -1
'Milan'.indexOf('') // = 0 !!

So if your search string is empty, the doSearch() will actually add all records with any city to the search results AND add the same record if it also has any country.

This last bit causes search results with multiple items with the same id. And react does not like that.

Also: if you have a record with city = "Paris", and country is "France", then you search query of "r" will lead to the same error. The letter "r" is in city -> record is added. Letter "r" is also in country -> same record will be added again .

Full solution also needs to ensure that each record is only added once:

if ( queryText == '' // if no search, then show all
  || s.support_title.toLowerCase().indexOf(queryText)!=-1
  || (s.city && s.city.toLowerCase().indexOf(queryText)!=-1)
  || (s.country && s.country.toLowerCase().indexOf(queryText)!=-1) ){
    queryResult.push(s);
  }

This ensures each record is added only once.

Sidenote: the way you fill your cards could be simplified, and has some unnecessary code. You could also do:

cards = this.props.data.map(function(s) {
  <a ...
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM