【问题标题】:Characters filter by property value in React.js在 React.js 中按属性值过滤字符
【发布时间】:2021-08-30 20:38:30
【问题描述】:

我正在尝试基于 Rick and Morty api 构建应用程序。 我想按物种过滤字符。 我为每个物种值创建了单独的组件 例如: Human.js

export const Human = ({ match }) => {
  const { species } = match.params;
  const [characterFilters, setCharacterFilters] = useState([]);
  useEffect(() => {
    try {
      fetch('https://rickandmortyapi.com/api/character?species=human')
        .then((res) => res.json())
        .then((res) => setCharacterFilters(res))
        .catch((err) => console.log(err));
    } catch (e) {
      console.log(e);
    }
  }, []);

  const { name, image } = characterFilters;

  return (
    <div>
      <h2>Name: {name}</h2>
      <div>
        <img alt={name} src={image}></img>
      </div>
    </div>
  );
};

在字符文件中,我根据选择的属性设置了条件

Characters.js

export const Characters = () => {
  const [characters, setCharacters] = useState();
  useEffect(() => {
    try {
      fetch(CHARACTERS_PAGE_URL)
        .then((res) => res.json())
        .then(({ results }) => {
          if (results && Array.isArray(results)) {
            setCharacters(results);
          }
        })
        .catch((err) => console.log(err));
    } catch (e) {
      console.log(e);
    }
  }, []);

  const handleSpeciesChange = (e) => {
    console.log("[e.target.value]", e.target.value);
    switch (e.target.value) {
      case "human":
        return <Human />;
        break;
      case "alien":
        return <Alien />;
        break;
      case "unknown":
        return <Unknown />;
        break;
      default:
        return;
    }
  };

  const handleStatusChange = (e) => {
    switch (e.target.value) {
      case "alive":
        return <Human />;
        break;
      case "dead":
        return <Alien />;
        break;
      case "unknown":
        return <Unknown />;
        break;
      default:
        return;
    }
  };

  if (!characters) {
    return <Loading />;
  }

  return (
    <div className="p-4 font-mono text-green-500 ">
      <div className="flex flex-row">
        <div className="m-4 ">
          <label>Species</label>
          <select name="species" id="species" onChange={handleSpeciesChange}>
            <option value="all">all</option>
            <option value="human">human</option>
            <option value="alien">alien</option>
            <option value="unknown">unknown</option>
          </select>
        </div>
        <div className="m-4">
          <label>Status</label>
          <select name="status" id="status" onChange={handleStatusChange}>
            <option value="all">all</option>
            <option value="alive">alive</option>
            <option value="dead">dead</option>
            <option value="unknown">unknown</option>
          </select>
        </div>
        <div className="m-4">
          <label>Gender</label>
          <select name="gender" id="gender">
            <option value="all">all</option>
            <option value="female">female</option>
            <option value="male">male</option>
            <option value="genderless">genderless</option>
            <option value="unknown">unknown</option>
          </select>
        </div>
      </div>
      <h1 className="text-4xl">Characters</h1>
      <Pagination data={characters} pageLimit={5} />
      <div className="grid grid-flow-col grid-cols-5 grid-rows-4 gap-4">
        {characters.map((character) => (
          <div key={character.id}>
            <Character character={character} />
          </div>
        ))}
      </div>
    </div>
  );
};

但我没有得到过滤字符。 我是反应新手。 请帮助我理解,我在这里做错了什么? 是否有可能创建一个通用的过滤器组件,我可以将其应用于不同的属性过滤器?

【问题讨论】:

    标签: reactjs filter


    【解决方案1】:

    你不能从回调中返回 jsx

    使过滤器被存储并仅从数组中呈现这些值:

    export const Characters = () => {
      const [characters, setCharacters] = useState();
      const [ speciesFilter, setSpeciesFilter ] = useState('');
      const [ status, setStatus] = useState('');
    
      useEffect(() => {
        try {
          fetch(CHARACTERS_PAGE_URL)
            .then((res) => res.json())
            .then(({ results }) => {
              if (results && Array.isArray(results)) {
                setCharacters(results);
              }
            })
            .catch((err) => console.log(err));
        } catch (e) {
          console.log(e);
        }
      }, []);
    
      const handleSpeciesChange = (e) => {
        console.log("[e.target.value]", e.target.value);
        setSpeciesFilter(e.target.value)
      };
    
      const handleStatusChange = (e) => {
        setStatus(e.target.value);
      };
    
      if (!characters) {
        return <Loading />;
      }
    
      let filteredCharacters = characters;
    
      if (speciesFilter) {
        filteredCharacters = filteredCharacters.filter(c => c.species === speciesFilter);
      }
    
     if (status ) {
        filteredCharacters = filteredCharacters.filter(c => c.status === status);
      }
    
      return (
        <div className="p-4 font-mono text-green-500 ">
          <div className="flex flex-row">
            <div className="m-4 ">
              <label>Species</label>
              <select name="species" id="species" onChange={handleSpeciesChange}>
                <option value="all">all</option>
                <option value="human">human</option>
                <option value="alien">alien</option>
                <option value="unknown">unknown</option>
              </select>
            </div>
            <div className="m-4">
              <label>Status</label>
              <select name="status" id="status" onChange={handleStatusChange}>
                <option value="all">all</option>
                <option value="alive">alive</option>
                <option value="dead">dead</option>
                <option value="unknown">unknown</option>
              </select>
            </div>
            <div className="m-4">
              <label>Gender</label>
              <select name="gender" id="gender">
                <option value="all">all</option>
                <option value="female">female</option>
                <option value="male">male</option>
                <option value="genderless">genderless</option>
                <option value="unknown">unknown</option>
              </select>
            </div>
          </div>
          <h1 className="text-4xl">Characters</h1>
          <Pagination data={characters} pageLimit={5} />
          <div className="grid grid-flow-col grid-cols-5 grid-rows-4 gap-4">
            {filteredCharacters.map((character) => (
              <div key={character.id}>
                <Character character={character} />
              </div>
            ))}
          </div>
        </div>
      );
    };
    

    上面的例子使用了一个可以改进的过滤器

    我在这里做错了什么?

    例如,您正在从回调中返回 JSX,

    onChange={handleStatusChange}
    

    这里你传递了一个函数,这个函数将传递给你处理的事件,问题是,从这个函数返回一个组件没有做任何事情,它不会告诉 React 渲染你返回的组件。

    相反,您可以将值从那里存储在状态中,并相应地做一些事情,例如,使用该值过滤数组

    是否有可能创建一个我可以使用的通用过滤器组件 可以申请不同的属性过滤器吗?

    这可以通过将字符传递给该组件和过滤器值来完成

    export const FilterCharacters = ({ characters, status, specie }) => {
      let filteredCharacters = characters;
    
      if (specie ) {
        filteredCharacters = filteredCharacters.filter(c => c.species === specie);
      }
    
     if (status ) {
        filteredCharacters = filteredCharacters.filter(c => c.status === status);
      }
    
      return filteredCharacters.map((character) => (
              <div key={character.id}>
                <Character character={character} />
              </div>
            ))
    }
    

    对于您的 Human 和特定物种组件,它调用 API 以获取过滤值,但我假设您最初已经获得了所有值,因此您只能从那里过滤,如果不是这样,您可以让 Human 更通用通过传递种类和状态,并使用该值查询 API

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-31
      • 1970-01-01
      • 1970-01-01
      • 2020-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-03
      相关资源
      最近更新 更多