有人可以帮我吗?我正在尝试通过上下文将数据从一个组件传递到另一个组件(从Search.js到Container.js)。但是,我收到类型错误。我在Web上搜索了许多问题,但没有找到答案。抱歉,如果这是孩子气的问题,我是新手。
Search.js:
import React, { Component } from 'react'
import { StyledFormSearchBar } from '../styles'
import { data } from '../data'
const SearchContext = React.createContext()
export default class Search extends Component {
constructor() {
super()
this.state = {
value: '',
results: [],
areResultsVisible: false
}
this.handleSearch = this.handleSearch.bind(this)
}
handleSearch(e) {
this.setState = {
value: e.target.value,
results: data.filter(item => {
return item.title.toLowerCase().includes(e.target.value.toLowerCase())
}),
areResultsVisible: true
}
}
render() {
return (
<StyledFormSearchBar>
<input type="search" name="search" className="border border-dark rounded" onSubmit={this.handleSearch}/>
<button type="submit" value="submit" className="bg-warning border-0 text-danger rounded-right position-relative">
<i className="fas fa-search"></i>
</button>
<SearchContext.Provider value = {{
...this.state,
handleSearch: this.handleSearch
}}>
{this.props.children}
</SearchContext.Provider>
</StyledFormSearchBar>
)
}
}
const SearchContextConsumer = SearchContext.Consumer
export { SearchContextConsumer }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Container.js:
import React from 'react'
import { Route, Switch } from "react-router-dom"
import { StyledDivGridContainer } from './styles'
import { SearchContextConsumer } from './header/Search'
import Carousel from './container/Carousel'
import MobilePhonesDiscount from './container/products/carousel/MobilePhonesDiscount'
import LaptopsDiscount from './container/products/carousel/LaptopsDiscount'
import TabletsDiscount from './container/products/carousel/TabletsDiscount'
import Products from './container/Products'
import SearchResults from './container/SearchResults'
import MobilePhones from './container/products/MobilePhones'
import Laptops from './container/products/Laptops'
import Tablets from './container/products/Tablets'
import ProductPage from './container/ProductPage'
import About from './container/About'
import ContactUs from './container/ContactUs'
export default function Container() {
return (
<StyledDivGridContainer>
<div className="no-gutters justify-content-between">
<SearchContextConsumer>
{
value => {
return (
!value.areResultsVisible
? <Switch>
<Route exact path="/" component={Carousel}/>
<Route exact path="/" component={Products}/>
</Switch>
: <Route exact path="/" component={SearchResults}/>
)
}
}
</SearchContextConsumer>
<Route path="/mobile_phones_discount" component={MobilePhonesDiscount}/>
<Route path="/laptops_discount" component={LaptopsDiscount}/>
<Route path="/tablets_discount" component={TabletsDiscount}/>
<Route path="/mobile_phones" component={MobilePhones}/>
<Route path="/laptops" component={Laptops}/>
<Route path="/tablets" component={Tablets}/>
<Route path="/product_page" component={ProductPage}/>
<Route path="/about" component={About}/>
<Route path="/contact_us" component={ContactUs}/>
</div>
</StyledDivGridContainer>
)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Search.js 在 Header.js 中:
import React, { Component } from 'react'
import { StyledHeader,
StyledSpanAccount } from './styles'
import { Link } from "react-router-dom"
import Catalogue from "./header/Catalogue"
import Search from "./header/Search"
export default class Header extends Component {
render() {
return (
<StyledHeader className="d-flex w-100 bg-light shadow justify-content-center">
<div className="d-flex flex-wrap justify-content-around align-items-center">
<div className="my-1 mr-3">
<Link to="/" className="logo">
<img src={require('../img/logo.webp')} alt="logo" className="img-tumbnail"/>
</Link>
</div>
<Catalogue/>
<Search/>
<div className="d-flex my-3">
<a href="#"><i className="fas fa-shopping-cart"></i></a>
<a href="#"><i className="fas fa-user-alt ml-3"></i></a>
<a href="#" className="d-flex flex-nowrap">
<StyledSpanAccount className="ml-2">Log in</StyledSpanAccount>
</a>
<a href="#" className="d-flex flex-nowrap">
<StyledSpanAccount className="ml-2">Sing up</StyledSpanAccount>
</a>
</div>
</div>
</StyledHeader>
)
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Container.js 在Header.js附近的 App.js 中:
import React from 'react';
import { Route } from "react-router-dom";
import { StyledDivWrapper } from './components/styles';
import Header from './components/Header';
import Container from './components/Container';
import Footer from './components/Footer';
export default function App() {
return (
<StyledDivWrapper className="d-flex flex-column">
<Route path="/" component={Header}/>
<Route path="/" component={Container}/>
<Route path="/" component={Footer}/>
</StyledDivWrapper>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
答案 0 :(得分:0)
您首先需要用上下文提供程序(Search
)包装顶级组件,因为上下文api的重点是自上而下传递数据,而不必显式传递每个级别的数据,否则上下文使用者首先将没有任何上下文可以使用:
<Search>
<App />
</Search>
此外,您需要使用prop value
来传递提供者的上下文,而不要使用任何prop(例如代码中的searchValue
):
<SearchContext.Provider value = {{
...this.state,
handleSearch: this.handleSearch
}}>
{this.props.children}
</SearchContext.Provider>
答案 1 :(得分:0)
问题是您的Container组件不在SearchContext.Provider中。为了确保您的代码正确运行,您必须在应用程序组件内部直接包含SearchContext Provider,以便它既是Search组件又是Container组件的共同父代。
首先,在另一个文件中创建一个上下文
// SearchContext.js
export const SearchContext = React.createContext();
const SearchContextConsumer = SearchContext.Consumer
export { SearchContextConsumer }
第二,创建一个充当提供者的组件
// SearchProvider.js
class SearchProvider extends React.Component {
constructor() {
super()
this.state = {
value: '',
results: [],
areResultsVisible: false
}
this.handleSearch = this.handleSearch.bind(this)
}
handleSearch(e) {
this.setState = {
value: e.target.value,
results: data.filter(item => {
return item.title.toLowerCase().includes(e.target.value.toLowerCase())
}),
areResultsVisible: true
}
}
render() {
return (
<SearchContext.Provider value = {{
...this.state,
handleSearch: this.handleSearch
}}>
{this.props.children}
</SearchContext.Provider>
)
}
}
现在您的搜索组件将变得简单
// Search.js
export default class Search extends Component {
render() {
return (
<SearchContext.Consumer>
{({handleSearch}) => (
<StyledFormSearchBar>
<input type="search" name="search" className="border border-dark rounded" onSubmit={handleSearch}/>
<button type="submit" value="submit" className="bg-warning border-0 text-danger rounded-right position-relative">
<i className="fas fa-search"></i>
</button>
</StyledFormSearchBar>
)}
</SearchContext.Consumer>
)
}
}
也不,您可以像这样在App.js中使用SearchProvider
export default function App() {
return (
<SearchProvider>
<StyledDivWrapper className="d-flex flex-column">
<Route path="/" component={Header}/>
<Route path="/" component={Container}/>
<Route path="/" component={Footer}/>
</StyledDivWrapper>
</SearchProvider>
);
}
答案 2 :(得分:0)
导入 createContext 之类的
import { React, createContext } from 'react';
export const MyContext = createContext();
这对我有帮助。