React Hooks:setState,什么时候真正生效?
React Hooks: setState, when does it actually take effect?
所以我想了解 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
未定义。我的控制台日志记录使这一点显而易见。
我希望在页面加载之前在 'component mounting' 上定义 page
和 pages
。所以我的问题是 setPages
什么时候真正设置页面?我可以在 useEffect 中同时分配两者吗?
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();
}, []);
异步操作需要时间。理论上可以通过不确定的时间量。因此,无法保证 运行 在安装组件之前获取数据。
相反,您需要表现得好像数据可能未定义并且具有处理该数据的应用程序状态。
至于在调用 setPages
后立即访问 pages 变量,这也会失败,因为 React 实际上是异步运行重新渲染的。
即使它同时运行,也有一个叫做closures
的东西,其中javascript在函数创建时拉入函数周围的所有变量,这样函数总是可以访问那些。 React Hooks 的工作原理是利用这些闭包来仅访问组件为 rendered/re-rendered 时的变量。出现这种情况的原因是因为每次重新渲染时,都会重新创建组件中的所有函数,从而创建一个新的闭包。
因此,这意味着您在使用 React 时需要牢记这些概念。
至于您的代码,Dlucidione 设置的结果解决方案是您最好的选择之一,除了设置单独的 useEffect 以在 pages
更改时更新 page
。
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');
}
重要说明,只要您可以将历史对象传递到那里,就可以在代码的任何地方使用它。我之前也在 redux thunks 中使用过它。
Redirect
的用法示例,无需在装载时重定向:
if(!pages && !page){
return <Redirect to="/404"/>
}
或在某些 JSX 中:
<div>
{!pages && !page && <Redirect to="/404"/>}
</div>
重定向 有 被渲染,这意味着它只能在组件的 return 语句中使用。
The way I'm understanding it: the redirect is based on if the
individual page is found in the mounting process, therefore the
redirecting process has to also be in the mounting process to check
before rendering anything to redirect or not.
这是正确的。当重定向本身挂载或更新时,如果条件正确,它将重定向。如果 Redirect 上有 path
或 from
属性(它们是彼此的别名),那么这会将 Redirect 限制为仅在该路径匹配时才起作用。如果路径不匹配,则重定向将不执行任何操作,直到路径更改为匹配(当然是卸载)。
Under the hood,Redirect只是在componentDidMount和componentDidUpdate中调用history.push
或history.replace
(通过Lifecycle组件),所以你可以随意使用。
所以我想了解 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
未定义。我的控制台日志记录使这一点显而易见。
我希望在页面加载之前在 'component mounting' 上定义 page
和 pages
。所以我的问题是 setPages
什么时候真正设置页面?我可以在 useEffect 中同时分配两者吗?
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();
}, []);
异步操作需要时间。理论上可以通过不确定的时间量。因此,无法保证 运行 在安装组件之前获取数据。
相反,您需要表现得好像数据可能未定义并且具有处理该数据的应用程序状态。
至于在调用 setPages
后立即访问 pages 变量,这也会失败,因为 React 实际上是异步运行重新渲染的。
即使它同时运行,也有一个叫做closures
的东西,其中javascript在函数创建时拉入函数周围的所有变量,这样函数总是可以访问那些。 React Hooks 的工作原理是利用这些闭包来仅访问组件为 rendered/re-rendered 时的变量。出现这种情况的原因是因为每次重新渲染时,都会重新创建组件中的所有函数,从而创建一个新的闭包。
因此,这意味着您在使用 React 时需要牢记这些概念。
至于您的代码,Dlucidione 设置的结果解决方案是您最好的选择之一,除了设置单独的 useEffect 以在 pages
更改时更新 page
。
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');
}
重要说明,只要您可以将历史对象传递到那里,就可以在代码的任何地方使用它。我之前也在 redux thunks 中使用过它。
Redirect
的用法示例,无需在装载时重定向:
if(!pages && !page){
return <Redirect to="/404"/>
}
或在某些 JSX 中:
<div>
{!pages && !page && <Redirect to="/404"/>}
</div>
重定向 有 被渲染,这意味着它只能在组件的 return 语句中使用。
The way I'm understanding it: the redirect is based on if the individual page is found in the mounting process, therefore the redirecting process has to also be in the mounting process to check before rendering anything to redirect or not.
这是正确的。当重定向本身挂载或更新时,如果条件正确,它将重定向。如果 Redirect 上有 path
或 from
属性(它们是彼此的别名),那么这会将 Redirect 限制为仅在该路径匹配时才起作用。如果路径不匹配,则重定向将不执行任何操作,直到路径更改为匹配(当然是卸载)。
Under the hood,Redirect只是在componentDidMount和componentDidUpdate中调用history.push
或history.replace
(通过Lifecycle组件),所以你可以随意使用。