以下是我在JSON中显示Redux存储状态内容的代码:
function ShowCartContents() {
// Convert object to JSON before rendering
const cartContentsJSON = JSON.stringify(useStore().getState())
return (
<div>
<h2>Cart contents: {cartContentsJSON}</h2>
</div>
);
}
// Works fine
一切都很好,但当我试图添加带有onClick属性的按钮来调用另一个函数时,我遇到了错误:
Error: could not find react-redux context value; please ensure the component is wrapped in a <Provider>
奇怪的是,我确实将<App>
封装在<Provider>
中,但出现了这个错误,我找不到发生这种情况的任何逻辑。这是我的App.js
:的开始
import './App.css';
import MenuItems from './components/Navbar/MenuItems';
import ReactDOM from 'react-dom';
import React, { useState } from 'react';
import { createStore } from 'redux';
import {AddItemToCart, DeleteItemFromCart, Counter} from './cart.js';
import Header from './header';
import Footer from './footer.js';
import { render } from "react-dom";
import { Provider } from "react-redux";
import { useSelector, useStore } from 'react-redux';
let store = createStore(Counter);
const rootElement = document.getElementById("root");
render(
<Provider store={store}>
<App />
</Provider>,
rootElement
);
const [customerInfo, setCustomerInfo] = useState([])
以下是我如何尝试使用OnClick为函数调用添加按钮:
function ShowCartContents() {
const cartContentsJSON = JSON.stringify(useStore().getState())
return (
<div>
<h2>Cart contents: {cartContentsJSON}</h2>
<button onClick={(e)=> {ShowCustomerInfo(e)}}>Proceed</button>
// Also tried: <button onClick={<ShowCustomerInfo/>}>Proceed</button>
</div>
);
}
这会触发上面的错误。这是我的ShowCustomerInfo
函数:
function ShowCustomerInfo(){
fetch(`http://127.0.0.1:5000/getCustomerInfo`)
.then(response => response.json())
.then(response => {
setCustomerInfo(response.result);
console.log(response.result);
});
return (
<div>
<h2>
{customerInfo}
</h2>
</div>
);
}
是什么导致了异常?如有任何建议,我们将不胜感激。
不能从事件处理程序(如onClick
(中呈现组件。事件处理程序可以更新状态并执行副作用,如API调用,但不能执行return
。如果你把组件作为一个函数调用,而不是正确地渲染它们,那么你会得到像"这样的错误;错误:找不到react redux上下文值;请确保该部件被包裹在CCD_ 7"中;。
相反,您希望从onClick
处理程序更新状态,并根据状态有条件地呈现不同的组件。您可以使用某种值,如boolean
状态showCustomerInfo
或number
状态page
。由于我们正在将数据加载到array
customerInfo
中,因此我们可以检查长度是否大于0
,并且只有在不为空时才显示客户信息。
export const App = () => {
const [customerInfo, setCustomerInfo] = useState([]);
// use this state so that we can disable hide the "Proceed"
// button immediately, before the fetch has completed
const [isLoading, setIsLoading] = useState(false);
const state = useSelector((state) => state);
const cartContentsJSON = JSON.stringify(state);
function loadCustomerInfo() {
console.log("clicked");
// can use async/await, but fetch is fine too
setIsLoading(true);
fetch(`http://127.0.0.1:5000/getCustomerInfo`)
.then((response) => response.json())
.then((response) => {
setIsLoading(false);
// could store this in redux instead
setCustomerInfo(response.result);
})
.catch((error) => {
console.error(error);
setIsLoading(false);
});
}
return (
<div>
<h2>Cart contents: {cartContentsJSON}</h2>
<button disabled={isLoading} onClick={() => loadCustomerInfo()}>
Proceed
</button>
{customerInfo.length > 0 && (
<div>
<h3>Customer Info</h3>
<p>{JSON.stringify(customerInfo)}</p>
</div>
)}
</div>
);
};
我在你的代码中看到了一些反模式,比如:
-
您的
App.js
创建了一个位于整个组件树const [customerInfo, setCustomerInfo] = useState([])
创建
rootElement
并在中使用之后ReactDOM.render
。您必须将此状态带入实际任何状态的组件都必须是React的一部分数据流,但你所做的实际上违反了这一点。重构该部分后,您可以使用此状态在您的
ShowCustomerInfo
中但是你应该把它称为<ShowCustomerInfo/>
,而不是ShowCustomerInfo()
,因为它呈现JSX
,你应该再次这样做,因为你想让这个组件成为React数据流的一部分,否则你只是把它当作一个常规函数。 -
这只是一个命名约定,但
App.js
文件不是定义<App/>
组件,但只是渲染它你的App.js
将是index.js
,因为它将是以ReactDOM.render
开始您的虚拟dom。
如果你在考虑第一部分的情况下进行更改,我相信你会解决这个问题。