IT이야기

ReactJS - 두 어레이의 일치하는 ID를 비교/필터링하고 결과를 이중 검색 기능에 사용하는 방법

cyworld 2022. 3. 15. 20:45
반응형

ReactJS - 두 어레이의 일치하는 ID를 비교/필터링하고 결과를 이중 검색 기능에 사용하는 방법

내 앱에 이중 검색 기능이 있었으면 좋겠어.한 번 검색하면 제목별로 책을 걸러낸다.다른 한편, 장르별로 책을 여과한다.두 검색 필터는 함께 작동해야 한다(검색어가제공된 경우 제목 및 장르로 필터링해야 함).

하지만 장르 검색 필터 적용이 어려워.

** 참고**: 생성 시 각 장르 태그에 동일하게 할당됨id딱 붙어있는 책처럼 말이야이런 식으로, 나는 검색되고 있는 장르와 관련된 모든 책을 끌어 올릴 수 있다.

개체:

book = { id: "id", title: "title", author: "author"}
genre = { id: "id", label: "label" }

상위 구성요소

export default function Books() {
  const [books, setBooks] = useState([])
  const [searchTitle, setSearchTitle] = useState("")
  const [genres, setGenres] = useState([]) 
  const [searchGenre, setSearchGenre] = useState("")

  useEffect(() => {
    fetch(`https://www.someapi.com/books`)
    .then(r => r.json())
    .then(setBooks)
  }, [])

  function handleAllGenres(val){
    setGenres([...genres, val])
  }

  const filterGenres = genres.filter(genre => {
    return genre.label.toLowerCase().includes(searchGenre.toLowerCase())
  })

  const filterBooks = books.filter(book => {
    return book.title.toLowerCase().includes(searchTitle.toLowerCase())
  })

  const filterBookGenres = filterBooks.filter(book => {    
    if (searchGenres.length > 0) {                 
      return filterGenres.some(genre => book.id === genre.id) 
    } else {
      return books
    }
  })

  const book = filterBookGenres.map(book => {
    return (
        <Book 
            key={book.id} 
            book={book}
            genres={genres}
            onAddGenre={handleAllGenres}
        />
    )
  })

  return (
    <div className="main-container">
      <SearchTitle 
        searchTitle={searchTitle} 
        onSearchTitle={setSearchTitle} 
      />
      <SearchGenre 
        searchGenre={searchGenre}
        onSearchGenre={setSearchGenre}
      />
      {book}
    </div>
  );
}

하위 구성 요소:

export default function Book({ book, onAddGenre }) 
    const [genreTags, setGenreTags] = useState([]) 

    function handleAddGenre(e) {
        const val = {
            id: book.id,
            label: e.target.value,
        }

        if (e.key === 'Enter' && val) {
            if (genreTags.find(genre => genre.toLowerCase() === val.toLowerCase())) {
              return
            }
            setGenreTags([...genreTags, val])
            onAddGenre(val)
            e.target.value = ""
        }
    }

    return (
        <div className="book-div">
            <p>{title}</p>
            <p>Written By: {author}</p>
        </div>
        <div className="tag-div">
            <ul> 
                { genreTags && genreTags.map(tag => {
                    return <li key={uuid()}> {tag.label} </li>  
                })}
            </ul>
        </div>
        <input 
            type="text" 
            placeholder="Add a genre"
            onKeyDown={handleAddGenre} 
        />
    );
}

구성 요소 검색:

export default function SearchTitle({ searchTitle, onSearchTitle }) {

    return (
        <div className="search">
            <input
                id="name-input" 
                placeholder="Search by title"
                value={search} 
                onChange={e => onSearch(e.target.value)} 
            />
        </div>
    );
}
export default function SearchGenre({ searchGenre, onSearchGenre }) {
    return (
        <div className="search">
            <input 
                id="tag-input"
                placeholder="Search by genre"
                value={searchGenre}
                onChange={e => onSearchTag(e.target.value)} 
            />
        </div>
    )
}

업데이트: 검색 기능이 이제 작동하지만 두 검색 기능 중 하나를 사용하여 재생한 후 태그가 사라지는 것을 발견.예를 들어, 검색 값을 입력하고 책 목록을 필터링한 다음 검색어를 삭제하면 태그가 사라진다.내 생각엔 책이 다시 리렌더구나.

이 리렌더를 방지하거나 내 검색 기능을 가지고 놀다가 태그가 사라지는 것을 방지할 수 있는 방법이 있는가?

모든 도움은 감사했다.고마워!

OnClick 핸들러 내부를 볼 수 없기 때문에(다른 구성 요소에 있음(다른 구성 요소에 있음).나는 즉시 가능한 이슈 하나를 본다. (이상하게도, 당신이 장르를 타이틀 검색이 아닌 이슈라고 말한 것을 고려하면, 이상하다.filterBooks당신은 가지고 있다book => { return title.toLowerCase()..., 그러나 그것은 그래야 한다.book => { return book.title.toLowerCase()...

또한, 이 코드 샘플에서는 설정하지 않고 있으며setGenres. 는genres비어있는 상태?

편집

이 리렌더를 방지하거나 내 검색 기능을 가지고 장난친 후 태그가 사라지지 않도록 하는 방법이 있는가?

예, 페이지를 새로 고치거나 마운트 해제하고 다시 마운트할 때까지 사용할 수 있는 해결 방법이 있습니다,Books구성 요소개체는 변이 가능한 데이터 구조이므로 새 키("태그")를 추가하도록 개체를 변이할 수 있다.이런 것들은 비록 그것이 지속된다고 해도 계속될 것이다.Book객체 분리 및 재장착우리는 이 일을 할 수 있다.handleAddGenreBook.js다음과 같다:

  function handleAddGenre(e) {
    const val = {
      id: book.id,
      label: e.target.value
    };

    if (e.key === "Enter" && val) {
      if (
        /**
         * Note that I made a small change here, 
         * adding 'labels' before the two toLowerCase methods
         */
        genreTags.find(
          (genre) => genre.label.toLowerCase() === val.label.toLowerCase()
        )
      ) {
        return;
      }
      /**
       * we mutate the book object here.  
       * This will persist until we reset the books state,
       * so searching doesn't make it disappear.
       */
      book.tags = book.tags ? [...book.tags, val] : [val];
      setGenreTags([...genreTags, val]);
      onAddGenre(val);
      e.target.value = "";
    }
  }

그러면, 우리는 책의 새 것을 통해 반복되어야 하기 때문에 그에 따라 렌더만 바꾸면 된다.tag새 레이블을 모두 찾을 수 있는 키

<ul>
  {book.tags &&
    book.tags.map((tag) => {
      return <li key={uuid()}> {tag.label} </li>;
  })}
</ul>

이것 좀 봐.

코드앤박스

import { useState } from "react";
import { Button, makeStyles } from "@material-ui/core";
import "./styles.css";

const genreList = [
  {
    id: 0,
    label: "horror",
    type: "fiction",
    desc: "these creepy crawler stories will leave you shaking in your boots!"
  },
  {
    id: 1,
    label: "action",
    type: "fiction",
    desc: "a fun, colorful adventure awaits!"
  },
  {
    id: 2,
    label: "history",
    type: "non-fiction",
    desc: "A blast from the past!"
  }
];

const bookList = [
  {
    id: 0,
    title: "My First Book",
    author: "Mint",
    genreId: 2
  },
  {
    id: 1,
    title: "My Second Book",
    author: "James Bond",
    genreId: 1
  },
  {
    id: 2,
    title: "Here's the Third!",
    author: "Batman",
    genreId: 1
  },
  {
    id: 3,
    title: "The Holy Fourth Empire",
    author: "John Snow",
    genreId: 0
  },
  {
    id: 4,
    title: "Remember Remember the Fifth of November!",
    autorh: "V",
    genreId: 0
  }
];

const useStyles = makeStyles({
  root: {
    flex: 1,
    display: "flex",
    flexDirection: "column"
  },
  header: {
    paddingBottom: "10px"
  },
  bookList: {
    height: "100px"
  }
});

export default function App() {
  const classes = useStyles();

  const [genres, setGenres] = useState(genreList);
  const [books, setBooks] = useState(bookList);
  const [isSelected, setIsSelected] = useState(null);

  return (
    <div className={classes.root}>
      <div className={classes.header}>
        {isSelected !== null ? (
          <h4>{genres[isSelected].label} Movies</h4>
        ) : (
          <h4>All Movies</h4>
        )}
      </div>
      <div className={classes.bookList}>
        {isSelected === null
          ? books.map((book) => <p>{book.title}</p>)
          : books
              .filter((book) => book.genreId === isSelected)
              .map((book) => <p>{book.title}</p>)}
      </div>
      <div className={classes.buttons}>
        <Button onClick={() => setIsSelected(0)}>Horror</Button>
        <Button onClick={() => setIsSelected(1)}>Action</Button>
        <Button onClick={() => setIsSelected(2)}>History</Button>
        <Button onClick={() => setIsSelected(null)}>All</Button>
      </div>
    </div>
  );
}

참조URL: https://stackoverflow.com/questions/68416095/reactjs-how-to-compare-filter-matching-ids-of-two-arrays-and-use-the-result-i

반응형