在子组件重新渲染时丢失路由器对象
Posted
技术标签:
【中文标题】在子组件重新渲染时丢失路由器对象【英文标题】:Losing router object on child component rerender 【发布时间】:2020-08-09 08:22:35 【问题描述】:我有一个父组件GoalList
映射到一个子组件:
data.goals.map((item, index) =>
return (
<Link
href= pathname: "/goal", query: id: item.id
key=`goal-item-$index`
>
<a>
<li>
<div>item.title</div>
</li>
</a>
</Link>
);
)
next/router
的页面:
import SingleGoal from "../components/SingleGoal";
const Single = () =>
return <SingleGoal />;
;
export default Single;
子组件:
const SingleGoal = () =>
const [id, setId] = useState("");
const router = useRouter();
useEffect(() =>
if (router.query.id !== "") setId(router.query.id);
, [router]);
const loading, error, data = useQuery(SINGLE_GOAL_QUERY,
variables: id: id ,
);
if (loading) return <p>Loading...</p>;
if (error) return `Error! $error.message`;
return (
<div>
<h1>data.goal.title</h1>
<p>data.goal.endDate</p>
</div>
);
;
当我点击父组件中的Link
时,item.id
被正确传输,SINGLE_GOAL_QUERY
正确执行。
但是,当我刷新 SingleGoal
组件时,路由器对象需要一瞬间来填充,并且我收到 GraphQL 警告:
[GraphQL error]: Message: Variable "$id" of required type "ID!" was not provided., Location: [object Object], Path: undefined
在一个类似的项目中,我之前给下一个/路由器的页面组件提供了道具,但这似乎不再起作用:
const Single = (props) =>
return <SingleGoal id=props.query.id />;
;
如何解决路由器对象的延迟问题?这是使用 getInitialProps 的情况吗? 感谢您的任何指导。
【问题讨论】:
【参考方案1】:在这种情况下,通过page
传输道具的秘诀是通过自定义_app
启用getInitialProps
。
之前:
const MyApp = ( Component, apollo, pageProps ) =>
return (
<ApolloProvider client=apollo>
<Page>
<Component ...pageProps />
</Page>
</ApolloProvider>
);
;
之后:
const MyApp = ( Component, apollo, pageProps ) =>
return (
<ApolloProvider client=apollo>
<Page>
<Component ...pageProps />
</Page>
</ApolloProvider>
);
;
MyApp.getInitialProps = async ( Component, ctx ) =>
let pageProps = ;
if (Component.getInitialProps)
// calls page's `getInitialProps` and fills `appProps.pageProps`
pageProps = await Component.getInitialProps(ctx);
// exposes the query to the user
pageProps.query = ctx.query;
return pageProps ;
;
现在唯一的缺点是不再生成静态页面,每个请求都使用服务器端渲染。
【讨论】:
【参考方案2】:您可以通过重新排序挂钩来使用路由器查询 id 设置组件内部的初始状态
const SingleGoal = () =>
const router = useRouter();
const [id, setId] = useState(router.query.id);
useEffect(() =>
if (router.query.id !== "") setId(router.query.id);
, [router]);
const loading, error, data = useQuery(SINGLE_GOAL_QUERY,
variables: id: id ,
);
if (loading) return <p>Loading...</p>;
if (error) return `Error! $error.message`;
return (
<div>
<h1>data.goal.title</h1>
<p>data.goal.endDate</p>
</div>
);
;
【讨论】:
这似乎并没有阻止useQuery
在 id 仍未定义未定义时执行。我收到关于未提供 ID 的相同控制台警告以上是关于在子组件重新渲染时丢失路由器对象的主要内容,如果未能解决你的问题,请参考以下文章
React:如何停止重新渲染组件或对同一路由更改路由器进行 API 调用
[react-router] React-Router 4怎样在路由变化时重新渲染同一个组件?