Несколько раскрывающихся фильтров не работают вместе в реагировать JS - PullRequest
1 голос
/ 24 марта 2019

В моем приложении «Реакция» у меня есть 3 выпадающих меню, первое из которых выбирает несколько свойств с опциями возрастания и убывания, второй фильтр по цвету волос и третий фильтр по профессиям. Однако, в зависимости от того, какой выпадающий список я использую первым, остальные 2 не будут работать потом, пока я не обновлю браузер. Данные извлекаются откуда-то с использованием axios, а выпадающие меню являются дочерними компонентами и реквизитами, передаваемыми в качестве функций обратного вызова.

Я думаю, мне нужно сбросить состояние для других критериев поиска, пробовал, но это не сработало. Я также искал решения для работы нескольких фильтров, но, похоже, я не в состоянии справиться со своими проблемами.

Вот мое начальное состояние компонента:

class HomePage extends Component {
constructor(props) {
super(props);
this.state = {
  data: [],
  imageIsLoaded: false,
  orderBy: "",
  order: "",
  profession: "",
  hairColor: "",
};
this.doOrderBy = this.doOrderBy.bind(this);
this.doOrder = this.doOrder.bind(this);
this.handleColor = this.handleColor.bind(this);
this.handlePro = this.handlePro.bind(this);
}

Вот обработчики

doOrderBy(e) {
const newOrderBy = e.target.value;
this.setState({
  orderBy: newOrderBy,
});
 }

doOrder(e) {
const newOrder = e.target.getAttribute("data-value");
this.setState({ order: newOrder });
}

doOrderBy - это массив ["name", "age", weight "..] doOrder is ["asc", "desc"]

handleColor(e) {
const uniqueHairColor = [
  ...new Set(this.state.data.map(item => item.hair_color)),
];
const newColor = [...e.target.selectedOptions].map(opt => opt.value);
const newValue = newColor == " " ? uniqueHairColor : newColor;
this.setState({
  hairColor: newValue,
});
}

handlePro(e) {
const newProfession = [...e.target.selectedOptions].map(opt => 
opt.value);
const allProfessions = this.state.data
  .map(item => item.professions)
  .flat(1);
const uniqueProfession = [...new Set(allProfessions)].sort();
const newValue = newProfession == " " ? uniqueProfession : 
newProfession;
this.setState({
  profession: newValue,
});
}

Вот логика сортировки:

render() {
const {data, imageIsLoaded, hairColor, orderBy, order, profession} 
=this.state;
let sorted = data;

if (order) {
  if (orderBy !== ("number of friends" && "number of professions")) 
   { sorted = _.orderBy(sorted, item => {
        return item[orderBy]}, order);
   } else if (orderBy === "number of friends") {
    sorted = _.orderBy(sorted, item => {
        return item.friends.length},order);
   } else {sorted = _.orderBy(sorted, item => {
       return item.professions.length}, order);
  }
} else if (hairColor) {
sorted = _.filter(sorted, item => _.includes(hairColor, 
item.hair_color));
} else if (profession) {
  sorted = _.filter(sorted, { professions: profession });
} else {
  sorted = data;
}

вот раскрывающиеся меню в качестве компонентов рендеринга:

         <OrderMenu
          doOrder={this.doOrder}
          order={order}
          orderBy={orderBy}
          doOrderBy={this.doOrderBy}
          placeholder="Select by..."
        />

        <HairMenu
          data={data}
          handleHairInput={this.handleColor}
          placeholder="Choose hair color..."
        />

        <ProfessionMenu
          data={data}
          handleInputPro={this.handlePro}
          placeholder="Choose profession..."
        />

и данные отображаются как

     <AnimalCards sorted={sorted}/>

В идеале мне бы хотелось, чтобы фильтры работали вместе, выполняя множественную фильтрацию одновременно. Но в тот момент, когда я использую первый фильтр, второй или третий не будет работать вообще, если я не обновлю браузер. Любая помощь, чтобы указать, что и где мне не хватает, было бы здорово. Спасибо.

import React, { Component, Fragment } from "react";

class AnimalCards extends Component {
render() {
const { sorted } = this.props;
const Jobless = <div>No profession to show</div>;
const NoFriends = <div>No friends to show</div>;
return (
  <Fragment>
    <div className="flip-card-container">
      {sorted.map(animal => {
        return (
          <div className="flip-card" key={animal.id}>
            <div className="flip-card-inner">
              {/* ---------------START front ----------- */}
              <div className="flip-card-front">
                <div
                  className="flip-card-front-top"
                  style={{ backgroundColor: animal.hair_color }}
                />
                <div className="img-container">
                  <img
                    className="img-circle"
                    src={animal.thumbnail}
                    alt={`${animal.name}`}
                    style={{ border: "5px solid white" }}
                  />
                </div>
                <div className="flip-card-front-bottom">
                  <div className="name">{animal.name}</div>
                  <div className="attributes">
                    <div className="age-group">
                      <img
                        className="ageIcon"
                        src={require("../images/axe.png")}
                        alt="ageIcon"
                      />
                      <div className="age">{animal.age + " "} 
      yrs</div>
                    </div>
                    <div className="weight-group">
                      <img
                        className="weightIcon"
                        src={require("../images/weight.png")}
                        alt="weightIcon"
                      />
                      <div className="weight"> {animal.weight} kg 
    </div>
                    </div>
                    <div className="height-group">
                      <img
                        className="ageIcon"
                        src={require("../images/height.png")}
                        alt="heightIcon"
                      />
                      <div className="height">{animal.height} cm 
</div>
                    </div>
                  </div>
                  <div className="professions">
                    Number of professions:
                    <div className="professions-num">
                      {animal.professions.length === 0
                        ? Jobless
                        : animal.professions.length}
                    </div>
                  </div>
                  <div className="friends">Number of friends:</div>
                  <div className="friends-num">
                    {animal.friends.length === 0
                      ? NoFriends
                      : animal.friends.length}
                  </div>
                </div>
              </div>
              {/* ------------START front ----------- */}
              {/* ------------START back ------------- */}
              <div className="flip-card-back">
                <div className="back-container">
                  <div className="back-header">Professions</div>
                  <div className="back-list">
                    {animal.professions.length === 0
                      ? Jobless
                      : animal.professions.join(", ")}
                  </div>
                </div>
                <div className="back-container">
                  <div className="back-header">Friends</div>
                  <div className="back-list">
                    {animal.friends.length === 0
                      ? NoFriends
                      : animal.friends.join(", ")}
                  </div>
                </div>
              </div>
              {/* -------------END back ------------- */}
            </div>
          </div>
        );
      })}
    </div>
  </Fragment>
 );
 }
 }
 export default AnimalCards;

Вот данные (в формате json), которые я получил:

fetchAnimals() {
const apiUrl =
 "https://raw.githubusercontent.com/rrafols/ 
 mobile_test/master/data.json";

 axios.get(apiUrl).then(({ data }) => {
  localStorage.setItem("data", data);
  this.setState({
    data: data.Brastlewark,
    imageIsLoaded: true,
  });
  });
}

componentDidMount() {
this.fetchAnimals();
}

1 Ответ

1 голос
/ 24 марта 2019

Проблема была на самом деле тривиальной. Вы использовали блок if-else-if!

if (order) { //If this is true the other else ifs will not be executed
  if (orderBy !== ("number of friends" && "number of professions")) 
   { sorted = _.orderBy(sorted, item => {
        return item[orderBy]}, order);
   } else if (orderBy === "number of friends") {
    sorted = _.orderBy(sorted, item => {
        return item.friends.length},order);
   } else {sorted = _.orderBy(sorted, item => {
       return item.professions.length}, order);
  }
} else if (hairColor) { // If the above condition was met this will not be checked
sorted = _.filter(sorted, item => _.includes(hairColor, 
item.hair_color));
} else if (profession) { //If any of the above was true this would not be checked
  sorted = _.filter(sorted, { professions: profession });
} else {
  sorted = data;
}

Итак ... превратить блоки if-else-if в отдельные / независимые блоки if! Также, небольшой совет по алгоритму, всегда выполняйте фильтрацию перед сортировкой!

Вот фиксированная логика.

render() {
  const {
    data,
    imageIsLoaded,
    hairColor,
    orderBy,
    order,
    profession
  } = this.state;

  let sorted = data;

  if (hairColor) {
    sorted = _.filter(sorted, item => _.includes(hairColor,
      item.hair_color));
  }

  if (profession) {
    sorted = _.filter(sorted, {
      professions: profession
    });
  }

  if (order) {
    if (orderBy !== ("number of friends" && "number of professions")) {
      sorted = _.orderBy(sorted, item => {
        return item[orderBy]
      }, order);
    } else if (orderBy === "number of friends") {
      sorted = _.orderBy(sorted, item => {
        return item.friends.length
      }, order);
    } else {
      sorted = _.orderBy(sorted, item => {
        return item.professions.length
      }, order);
    }
  }


}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...