繁体   English   中英

反应:如何将 state 从子组件传递给父组件

[英]React : how to pass a state from child to parent component

我想在子组件PokemonSearchBar.jsx中传递filteredData数据,以便我可以在父组件PokemonList.jsx中使用它到 map 只过滤口袋妖怪。 换句话说,当我进行搜索时,搜索组件会将我输入的e.target.value中的字符与data数组(填充所有口袋妖怪名称)中的字符进行比较,该数组作为道具传递父组件PokemonList.jsx 如果e.target.valuedata数组之间有一些共同的字符, filteredData将只从输入中接收与e.target.value的共同字符的口袋妖怪。

有什么方法可以将filteredData state 作为道具传递给父组件?

这是子组件PokemonSearchBar.jsx

import React, { useState } from 'react';
import { Link } from 'react-router-dom';

import './PokemonSearchBar.css';

import SearchIcon from '@mui/icons-material/Search';
import CloseIcon from '@mui/icons-material/Close';

export default function PokemonSearchBar({ placeholder, data }) {
    const [filteredData, setFilteredData] = useState([]);
    const [wordEntered, setWordEntered] = useState("");

    const handleFilter = (e) => {
        const searchWord = e.target.value;
        setWordEntered(searchWord);
        const newFilter = data.filter(value => {
            return (value.name.toLowerCase().includes(searchWord.toLowerCase()));
        });
        
        if(searchWord === "") {
            setFilteredData([]);
        } else {
            setFilteredData(newFilter);
        }
    }

    const clearInput = (e) => {
        setWordEntered("");
        setFilteredData([]);
    }

  return (
    <div className='search'>
        <div className="row" style={{ display: 'flex', justifyContent: 'center' }}>
            <div className="col-3"></div>
            <div className="col-6">
                <div className="searchInputs" style={{ display: 'flex', justifyContent: 'center'}}>
                    <input type="text" className="form-control rounded" placeholder={placeholder} onChange={handleFilter} value={wordEntered} />
                    {filteredData.length === 0 ? <button type="button" className="btn btn-primary"><SearchIcon /></button> : <button type="button" className="btn btn-warning"><CloseIcon onClick={clearInput} /></button>}
                </div>
            </div>
            <div className="col-3"></div>
        </div>
        {filteredData.length !== 0 &&
            <div className="dataResult mx-auto" style={{ display: 'flex', justifyContent: 'center' }}>
                <ul>
                    {filteredData.slice(0, 15).map((pokemon) => {
                        return (<li style={{ listStyleType: 'none', textDecoration: 'none'}} className="dataItem"><Link to="/" className="a" style={{ textDecoration: 'none', color: 'black' }}>{pokemon.name}</Link></li>)
                    })}
                </ul>
            </div>
        }
    </div>
  )
}

这是父组件PokemonList.jsx

import React, { Component } from 'react'
import axios from 'axios'
import ReactPaginate from 'react-paginate';

import PokemonCard from './PokemonCard';
import PokemonSearchBar from './PokemonSearchBar';


export default class PokemonList extends Component {
    state = {
        url: "https://pokeapi.co/api/v2/pokemon?limit=100000&offset=0",
        pokemon: [], // on créé un objet (qui va devenir un tableau) pokemon null c'est où on va enregistrer le json
        pageNumber: 0,
        pokemonsPerPage: 16
    };

    async componentDidMount() {
        const res = await axios.get(this.state.url); // on attend de récupérer les pokemon avant d'exectuer la suite de la fonction
        console.log(res.data['results']);
        this.setState({pokemon: res.data['results']}); // on passe un objet dans le state et on affecte à pokemon le tableau résultats de la data de l'url
        // setState re-render seulement les éléments qu'il faut re-rendre
    };

    render() {
        console.log(this.state.pokemon);

        const pagesVisited = this.state.pageNumber * this.state.pokemonsPerPage;

        const displayUsers = this.state.pokemon
            .slice(pagesVisited, pagesVisited + this.state.pokemonsPerPage)
            .map((pokemon) => {
                return (
                    <PokemonCard 
                        key={pokemon.name} // on utilise le props name comme clé unique car chaque nom de pokemon est unique
                        name={pokemon.name} // c'est le props name dans le pokemonCard
                        url={pokemon.url} // c'est le props url dans le pokemonCard
                    /> // on génère autant de cartes qu'il y a de pokemons dans le tableau results
                )
            });

        const pageCount = Math.ceil(this.state.pokemon.length / this.state.pokemonsPerPage); // ceil() permet d'arrondir au supérieur

        const changePage = ({selected}) => {
            this.setState({pageNumber: selected})
        }

        return (
            <React.Fragment>
                <PokemonSearchBar  data={this.state.pokemon} placeholder="Enter a Pokemon name" />
                <br />
                {this.state.pokemon ? ( // s'il y a quelquechose dans le state
                    <div className='row'>
                        {displayUsers}
                        <div style={{ display: 'flex', justifyContent: 'center'}}>
                            <ReactPaginate 
                                previousLabel={"previous"}
                                nextLabel={"Next"}
                                pageCount={pageCount}
                                onPageChange={changePage}
                                containerClassName={"paginationButtons"}
                                previousLinkClassName={"previousButton"}
                                nextLinkClassName={"nextButton"}
                                disabledClassName={"paginationDisabled"}
                                activeClassName={"paginationActive"}
                            />
                        </div>
                    </div>
                ) : (<h2>Loading Pokemon</h2>)} 
                {/* S'il n'y a rien dans le state afficher que le pokemon est en train de charger */}
            </React.Fragment>
        )
    }
}

在 React 中,基本上有 3 种方式来发送数据:

  1. 通过作为道具传递的回调;
  2. 通过 Store(Redux 或 Context API 或其他)
  3. 通过本机自定义 Javascript 事件

您的用例可以通过 prop 实现:

import React, { useState } from 'react';
import { Link } from 'react-router-dom';

import './PokemonSearchBar.css';

import SearchIcon from '@mui/icons-material/Search';
import CloseIcon from '@mui/icons-material/Close';

export default function PokemonSearchBar({ placeholder, data, onDataFiltered }) {
    const [filteredData, setFilteredData] = useState([]);
    const [wordEntered, setWordEntered] = useState("");

    const handleFilter = (e) => {
        const searchWord = e.target.value;
        setWordEntered(searchWord);
        const newFilter = data.filter(value => {
            return (value.name.toLowerCase().includes(searchWord.toLowerCase()));
        });
        
        if(searchWord === "") {
            setFilteredData([]);
            onDataFiltered([])
        } else {
            setFilteredData(newFilter);
            onDataFiltered(newFilter)
        }
    }

    const clearInput = (e) => {
        setWordEntered("");
        setFilteredData([]);
    }

  return (
    <div className='search'>
        <div className="row" style={{ display: 'flex', justifyContent: 'center' }}>
            <div className="col-3"></div>
            <div className="col-6">
                <div className="searchInputs" style={{ display: 'flex', justifyContent: 'center'}}>
                    <input type="text" className="form-control rounded" placeholder={placeholder} onChange={handleFilter} value={wordEntered} />
                    {filteredData.length === 0 ? <button type="button" className="btn btn-primary"><SearchIcon /></button> : <button type="button" className="btn btn-warning"><CloseIcon onClick={clearInput} /></button>}
                </div>
            </div>
            <div className="col-3"></div>
        </div>
        {filteredData.length !== 0 &&
            <div className="dataResult mx-auto" style={{ display: 'flex', justifyContent: 'center' }}>
                <ul>
                    {filteredData.slice(0, 15).map((pokemon) => {
                        return (<li style={{ listStyleType: 'none', textDecoration: 'none'}} className="dataItem"><Link to="/" className="a" style={{ textDecoration: 'none', color: 'black' }}>{pokemon.name}</Link></li>)
                    })}
                </ul>
            </div>
        }
    </div>
  )
}

然后,您将像这样声明它:

 <PokemonSearchBar
    data={this.state.pokemon}
    placeholder="Enter a Pokemon name"
    onDataFiltered={(newData) => {
       console.log("do something with the new data", newData);
    }}
/>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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