所以我正在尝试在 react 中构建一个单页应用程序。
我想要的:在页面上,您可以像往常一样访问不同的页面。在一个页面(索引(上,我想要一个用户可以单击的按钮,该按钮将另一个组件展开到带有表单的视图中。展开后,此组件或窗体应在所有页面上可见。
问题:索引页从 API 加载一些数据,因此当索引组件挂载时,会进行获取调用。但是当用户单击"展开表单"按钮时,父组件的状态会按预期更新,但子组件会重新呈现,这会导致索引组件再次获取数据,这不是我想要的。
我尝试了什么
// Parent Component
const App => props => {
const [composer, setComposer] = useState({
// ...
expanded: false,
});
const expandComposer = event => {
event.preventDefault();
setComposer({
...composer,
expanded: true
});
return(
// ...
<Switch>
// ...
<Route
exact path={'/'}
component={() => (<Index onButtonClick={expandComposer}/>)}
// ....
{composer.expanded && (
<Composer/>
)};
);
};
// Index Component
const Index=> props => {
const [isLoading, setIsLoading] = useState(true);
const [data, setData] = useState([]);
useEffect(()=> {
// load some data
}, []);
if(isLoading) {
// show spinner
} else {
return (
// ...
<button onClick={props.onButtonClick}>Expand Composer</button>
// ...
);
};
};
因此,使用我的方法,单击按钮时,索引组件会再次获取数据,并且微调器在短时间内可见。但我不想重新挂载索引,或者如果可能的话至少重新加载数据
这里有两个问题。首先,默认情况下,React
将在父组件更新时重新呈现所有子组件。若要避免此行为,应显式定义组件应更新的时间。在基于类的组件中,PureComponent
或shouldComponentUpdate
是要走的路,而在功能组件中,React.memo
等同于PureComponent
。仅当其中一个PureComponent
发生props
更改时,才会更新。所以你可以像这样实现它:
const Index = () =>{/**/}
export default React.memo(Index)
但这不会解决您的问题,因为第二个问题。PureComponent
和React.memo
props
中执行shallow comparison
,并且您正在传递一个内联函数作为prop
,它将在每个shallow comparison
中返回false
,因为每次渲染都会创建一个函数的新实例。
<Child onClick={() => this.onClick('some param')} />
这实际上会在每次渲染时创建一个新函数,导致比较始终返回false
。解决方法是将参数作为第二个prop
传递,如下所示
<Child onClick={this.onClick} param='some param' />
在里面Child
<button onClick={() => props.onClick(props.param)} />
现在,您没有在渲染上创建任何函数,只是将this.onClick
的引用传递给您的孩子。
我不完全熟悉你的 React 风格,我不使用它们特殊的状态函数。
为什么不在父状态中添加一个布尔值,称为"fetched"。
if (!fetched(fetch(params, ((=>setState({ fetched: true ((;
希望这有帮助
愚蠢的我,我在定义路由时使用了component={() => ...}
而不是render={() => ...}
。如 react router 文档中所述,使用component
始终会重新渲染组件。杜波卡斯的答案现在非常有效:)