我有一个Blog组件,其中有一个Search组件。我需要有权访问我的Blog组件中的searchResults
变量。如何将其从搜索组件传递到博客组件?
这是父项(博客组件):
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import Pagination from "react-pagination-js";
import Spinner from '../Spinner/Spinner';
import { Link } from 'react-router-dom';
import Footer from '../Footer/Footer.jsx';
import CustomHeader from '../CustomHeader/CustomHeader.jsx';
import Search from '../Search/Search.jsx';
const Blog = () => {
let title = 'Articles'
let [posts, setPosts] = useState([]);
let [isMounted] = useState(false)
let [currentPage, setCurrentPage] = useState(1);
let [loading, setLoading] = useState(false);
let [isVisible] = useState(true);
const [postsPerPage] = useState(5);
const GET_POSTS_API = process.env.REACT_APP_GET_POSTS_API;
useEffect(() => {
const fetchPosts = async () => {
isMounted = true;
setLoading(true);
if (isMounted) {
let res = await axios.get(GET_POSTS_API);
setPosts(res.data);
}
setLoading(false);
};
fetchPosts();
}, []);
isMounted = false
// Get current posts
const indexOfLastPost = currentPage * postsPerPage;
const indexOfFirstPost = indexOfLastPost - postsPerPage;
const currentPosts = posts.slice(indexOfFirstPost, indexOfLastPost);
let totalPagesGenerated = posts.length / postsPerPage;
let totalPagesGeneratedCeiled = Math.ceil(totalPagesGenerated);
if (loading) {
return <Spinner />
}
// Change page
const paginate = (pageNumber) => {
Math.ceil(totalPagesGenerated)
if (pageNumber > 0 && pageNumber <= totalPagesGeneratedCeiled) {
setCurrentPage(pageNumber);
}
}
return (
<div>
<CustomHeader
title={title}
/>
<Search />
<div className="row">
<div className="column">
{currentPosts.map(post => (
<div key={post._id} className='post'>
<img className="post-container__image" src={post.picture} alt="avatar" />
<div className="post-container__post">
<div className="post-container__text">
<h2 className="post-container__title">{post.title}</h2>
<p className="post-container__date">{post.date}</p>
<p className="post-info-container__text">{post.postContent.substr(0, 310) + "..."}</p>
<Link to={`/post/${post._id}`} className="read-more-btn">
<button className="read-more-btn">Read more</button>
</Link>
</div>
</div>
</div>
))}
<Pagination
currentPage={currentPage}
currentPosts={currentPosts}
showFirstLastPages={true}
sizePerPage={postsPerPage}
totalSize={posts.length}
totalPages={posts.length}
changeCurrentPage={paginate}
/>
</div>
</div>
<Footer />
</div>
);
};
export default Blog;
这是子级(搜索组件):
import React, { Component } from "react";
import Spinner from '../../components/Spinner/Spinner.jsx';
import { Link } from 'react-router-dom';
import axios from "axios";
class Search extends Component {
constructor(props) {
super(props);
this.state = {
searchResults: [],
isLoading: false,
isSearchStringFound: true,
placeholder: ''
}
}
handleSearchQuery = (event) => {
const SEARCH_RESULTS_ENDPOINT = process.env.REACT_APP_SEARCH_ENDPOINT;
let searchString = document.querySelector(".search-input").value;
if (event.keyCode === 13) {
this.setState({ ...this.state, isLoading: true });
axios.post(SEARCH_RESULTS_ENDPOINT, {
searchString: searchString,
}).then(response => {
this.setState({ ...this.state, searchResults: response.data });
if (response.data.length === 0) {
this.setState({ ...this.state, isSearchStringFound: false });
}
else if (response.data.length > 0) {
this.setState({ ...this.state, isSearchStringFound: true });
}
this.setState({ ...this.state, isLoading: false });
});
this.setState({ ...this.state, placeholder: searchString });
}
};
render() {
if (this.state.isLoading) {
return <Spinner />
}
return (
<div>
<div>
<input
type="text"
placeholder={this.state.placeholder}
className="search-input"
onKeyDown={(e) => this.handleSearchQuery(e)}
/>
<div className="results-container">
<div>
{this.state.isSearchStringFound === false ? <div className="no-results-found">No results were found</div> : this.state.searchResults.map(result => (
<div key={result._id} className="results-box" >
<img src={result.picture} alt="avatar" className="results-container-img" />
<div className="results-box-body">
<div>
<h2>{result.title.toUpperCase()}</h2>
<p>{result.postContent.substr(0, 310) + "..."}</p>
<p>{result.date}</p>
<Link to={`/post/${result._id}`} className="read-more-btn">
<button className="read-more-btn">Read more</button>
</Link>
</div>
</div>
</div>
))}
</div>
</div>
</div>
</div>
);
}
}
export default Search;
是否可以在不使用Redux的情况下执行此操作?
答案 0 :(得分:0)
子组件应该从父类中获取一个回调属性。有点像按钮的工作方式:
<Button onClick={this.onButtonClick}
您要做的是
<SearchComponent onSearchResults={this.onResults}
然后,在搜索组件中,您可以调用this.props.onSearchResults(searchResults);
答案 1 :(得分:0)
您可以使用回调函数来做到这一点。
基本上,您将一个函数传递给子组件,子组件将触发该函数,而父组件将具有该值。
以下是应如何实施的简单示例:
父母:
decimal(10,2)
孩子:
const Parent = () => {
const onSearchResult = searchResults => {
console.log(searchResults)
}
return (
<>
I am the parent component
<Child onSearchResult={onSearchResult} />
</>
)
}
答案 2 :(得分:0)
我更喜欢两种方法将变量传递给子组件。它们分别在不同情况下很有用
方法1:使用属性=>道具
如果您的组件树未深度嵌套,则此方法很有用。例如,您希望将变量从父级传递给子级。
嵌套组件如下
const ParentComponent = () => {
const [variable, setVariable] = useState(0);
return (
<ChildComponent variable={variable} setVariable={setVariable} /> //nested within ParentComponent, first level
)
}
const ChildComponent = (props) => {
return(
<>
<div>prop value is {props.variable}</div> //variable attribute available through component props
<button onClick={props.setVariable(prevValue => prevValue+1}>add +1</button> //set value in parent through callBack method
</>
)
}
如果您具有高度嵌套的组件层次结构,则情况会有些混乱。可以说,ChildComponent返回了另一个组件,并且您希望将variable
传递到该组件,但是ChildComponent不需要该变量,您最终会遇到这种情况
const ParentComponent = () => {
const [variable, setVariable] = useState(false);
return (
<ChildComponent someProp={variable}/> //nested within ParentComponent, first level
)
}
const ChildComponent = (props) => {
return(
<AnotherCustomComponent someProp={props.someProps}/> //someProp attribute available through component props
)
}
const AnotherCustomComponent = (props) => {
return(
<div>prop value is {props.someProp}</div> //someProp attribute available through component props
)
}
即使ChildComponent不需要该道具,它也需要通过道具将其推入其子组件。这就是所谓的“钻探”。这是一个简单的示例,但是对于更复杂的系统,它可能会变得非常混乱。为此,我们使用...
方法2:上下文API CodeSandbox
Context API提供程序提供了一种向子组件提供状态的灵巧方法,而不会导致最终钻探情况。它要求设置Provider
,并将其值提供给可以使用上下文的任何Consumers'. Any component that is a child of the
Provider`。
首先创建一个上下文。
CustomContext.js
import React from 'react';
const CustomContext = React.createContext();
export function useCustomContext() {
return React.useContext(CustomContext);
}
export default CustomContext;
下一步是实现提供程序,并为其提供值。我们可以使用较早版本的ParentComponent并添加Context提供程序
import CustomContext from './CustomContext'
const ParentComponent = () => {
const [variable, setVariable] = useState(false);
const providerState = {
variable,
setVariable
}
return (
<CustomContext.Provider value={providerState} >
<ChildComponent />
</CustomContext.Provider>
)
}
现在,嵌套在Provider
我们嵌套的子组件看起来像这样
const ChildComponent = (props) => {
return(
<AnotherCustomComponent/> //Notice we arent passing the prop here anymore
)
}
const AnotherCustomComponent = (props) => {
const {variable, setVariable} = useCustomContext(); //This will get the value of the "value" prop we gave to the provider at the parent level
return(
<div>prop value is {variable}</div> //variable pulled from Context
)
}
如果两次使用ParentComponent,则ParentComponent的每个实例将为其子级提供其自己的“ CustomContext”。
const App() {
return (
<>
<ParentComponent/>
<ParentComponent/>
</>
}