我们正在升级我们的React App,经过几个小时的痛苦已经意识到将包装的组件传递到React Router(V4和其他人)会导致组件每次重新安装时都会“重新安装”传入。
这是包裹的组件......
export default function preload(WrappedComponent, props) {
class Preload extends React.Component {
componentWillMount() {
getDataForComponent(props);
}
render() {
return <WrappedComponent {...props} />;
}
}
return Preload;
}
以下是我们如何使用它......
const FlagsApp = (props) => {
return (
<Route path="/report/:reportId/flag/:id/edit" component{preload(FlagForm, props)} />
);
};
无论何时我们发送操作然后接收更新,组件都会重新安装,从而导致很多问题。根据github上的this thread,组件将重新安装,如果:
- 在渲染过程中调用withRouter(..),每次都会创建一个新的组件类
- 您将每个渲染的新函数传递给Route.component,例如:使用匿名功能 {...}} /&gt ;,这也会创建一个新组件
如果我直接传递FlagForm
组件,问题就解决了,但我无法利用preload
功能。
那么,如何在没有组件重新安装的情况下实现相同的结果?
提前感谢您的帮助!
答案 0 :(得分:1)
Route
在每次更新中添加新组件的原因是每次都通过preload
为其分配了一个新类。
事实上,每次拨打preload
始终会返回 不同 匿名类,甚至
当使用相同的参数调用时:
console.log( preload(FlagForm,props) != preload(FlagForm,props) ) // true
因此,问题是在preload
组件FlagsApp
方法中调用render
,首先将其移到该范围之外:
const PreloadedFlagForm = preload(FlagForm, props) //moved out
const FlagsApp = (props) => {
return (
<Route path="/report/:reportId/flag/:id/edit"
component={PreloadedFlagForm} /> //assign component directly
);
};
这样Route
的组件在更新之间不会发生变化。
现在关于props
的那个挥之不去的preload
参数:这实际上是一种反模式。传递props
的正确方法只是标准方式:
const PreloadedFlagForm = preload(FlagForm) //drop the props arg
const FlagsApp = (props) => {
return (
<Route path="/report/:reportId/flag/:id/edit"
component={<PreloadedFlagForm {...props} />} //spread it in here instead
/>
);
};
因此preload
的代码变为:
export default function preload(WrappedComponent) {
class Preload extends React.Component {
componentWillMount() {
getDataForComponent(this.props);
}
render() {
return <WrappedComponent {...this.props} />;
}
}
return Preload;
}
希望有所帮助!
答案 1 :(得分:0)
如果像我一样你没有阅读说明,答案就在于render
组件的<Route>
道具
https://reacttraining.com/react-router/web/api/Route/render-func
渲染:func
这样可以方便地进行内联渲染和包装,而不会出现上述不需要的重新安装。
因此,您必须使用component
道具,而不是将包装函数传递到render
道具中。但是,您不能像上面那样传递包装组件。我仍然不完全理解发生了什么,但为了确保params正确传递,这是我的解决方案。
My Preload wrapper函数现在是一个React组件,用于呈现Route ...
export default class PreloadRoute extends React.Component {
static propTypes = {
preload: PropTypes.func.isRequired,
data: PropTypes.shape().isRequired,
location: PropTypes.shape({
pathname: PropTypes.string.isRequired,
}),
}
componentWillMount() {
this.props.preload(this.props.data);
}
componentWillReceiveProps({ location = {}, preload, data }) {
const { location: prevLocation = {} } = this.props;
if (prevLocation.pathname !== location.pathname) {
preload(data);
}
}
render() {
return (
<Route {...this.props} />
);
}
}
然后我就这样使用它......
const FlagsApp = (props) => {
return (
<Switch>
<PreloadRoute exact path="/report/:reportId/flag/new" preload={showNewFlagForm} data={props} render={() => <FlagForm />} />
<PreloadRoute exact path="/report/:reportId/flag/:id" preload={showFlag} data={props} render={() => <ViewFlag />} />
<PreloadRoute path="/report/:reportId/flag/:id/edit" preload={showEditFlagForm} data={props} render={() => <FlagForm />} />
</Switch>
);
};
我在this.props.preload
和componentWillMount
中同时调用componentWillReceiveProps
的原因是因为我在导航时遇到了PreloadRoute
组件无法重新安装的相反问题,所以这解决了这个问题。
希望这能为很多人节省很多时间,因为我花了很多时间才使这个工作得恰到好处。我认为这是成本最低的成本!