所以我试图理解 React Hooks 以及如何使用它们。我可以在组件中进行获取,如下所示:
var [pages,setPages] = useState();
var [page,setPage] = useState();
async function fetchData() {
await fetch(`https://myBackend/pages`)
.then(response => response.json())
.then(response => {
setPages(response);
console.log(pages[0].title);
})
.then(()=>{
// AT THIS STAGE, pages IS UNDEFINED
setPage(pages.filter(singlepage=> {
return singlepage.url == props.match.params.url;
}))
}
.catch(err => setErrors(err));
}
useEffect(() => {
fetchData();
console.log(pages[0].title);
return () => {
console.log('unmounting...');
}
},[]);
我调用我的后端以获取所有页面,这工作正常,就好像我编码pages[0].title
它会呈现一样。但是当我尝试在useEffect
钩子中访问pages
中的特定值时,对我来说分配page
,它给了我pages
未定义的错误。我的控制台日志记录使这一点显而易见。
我希望在页面加载之前在"组件安装"上定义page
和pages
。所以我的问题是setPages
什么时候真正设置页面?我是否可以在useEffect中分配两者,并基于彼此分配?
异步操作需要时间。理论上可以经过不确定的时间。因此,无法保证在挂载组件之前获取数据。
相反,您需要表现得好像数据可能是未定义的,并且具有处理该数据的应用程序的状态。
至于在调用setPages
后立即访问页面变量,这也将失败,因为 React 实际上是异步运行重新渲染的。
即使它同时运行,也有一种叫做closures
的东西,javascript 在创建函数时会拉入函数周围的所有变量,以便函数始终可以访问这些变量。React Hooks 的工作原理是利用这些闭包来仅访问组件渲染/重新渲染时的变量。之所以会这样,是因为每次重新渲染时,组件中的所有函数都会重新创建,从而创建新的闭包。
所以,这意味着在使用 React 时,你需要牢记这些概念。
至于你的代码,Dlucidione设置的结果解决方案是你最好的选择之一,除了设置一个单独的useEffect来更新page
当pages
发生变化时。
const history = useHistory(); //from react-router-dom
useEffect(() => {
async function fetchData() {
return await fetch(`https://myBackend/pages`)
.then((response) => response.json())
.then((response) => {
setPages(response);
})
.catch((err) => setErrors(err));
}
fetchData();
return () => {
console.log('unmounting...');
};
}, []);
useEffect(() => {
const url = props.match.params.url;
if (!pages || !url) return;
// Using Array#find here because I assume based on the name, you want one page rather than an array
const page = pages.find((singlepage) => {
return singlepage.url === url;
});
if (!page) {
// This will change the route if a page isn't found.
history.push('/404');
}
setPage(page);
}, [pages, props.match.params.url, history]);
Redirect
和history.push
的工作方式不同。Redirect
是声明性导航方法,而history.push
是编程方法。
history.push
的用法示例:
if (!page) {
// This will change the route if a page isn't found.
history.push('/404');
}
重要提示,只要您可以将 history 对象传递给那里,就可以在代码中的任何位置使用。我以前也曾在 redux thunks 中使用过它。
Redirect
在挂载时不重定向的示例用法:
if(!pages && !page){
return <Redirect to="/404"/>
}
或者在某些 JSX 中:
<div>
{!pages && !page && <Redirect to="/404"/>}
</div>
必须呈现重定向,这意味着它只能在组件的 return 语句中使用。
我理解它的方式:重定向基于如果 在安装过程中可以找到单个页面,因此 重定向过程也必须在安装过程中进行检查 在渲染任何要重定向或不重定向的内容之前。
这是正确的。当重定向本身装载或更新时,如果条件正确,它将重定向。如果重定向上有path
或from
道具(它们是彼此的别名(,那么这会限制重定向仅在该路径匹配时才起作用。如果路径不匹配,重定向将不执行任何操作,直到路径更改为匹配(或者当然,它会卸载(。
在后台,重定向只是在 componentDidMount 和 componentDidUpdate 中调用history.push
或history.replace
(通过生命周期组件(,所以你可以随心所欲。
useEffect(() => {
const fetchData = async () => {
try {
// Make a first request
const result = await axios.get(`firstUrl`);
setPages(result);
// here you can use result or pages to do other operation
setPage(result.filter(singlepage=> {
return singlepage.url == props.match.params.url;
or
setPage(pages.filter(singlepage=> {
return singlepage.url == props.match.params.url;
}))
} catch (e) {
// Handle error here
}
};
fetchData();
}, []);