我正在尝试将展示组件与容器组件分开。我有一个 SitesTable
和一个 SitesTableContainer
。容器负责触发 redux 操作以根据当前用户获取适当的站点。
问题是在容器组件最初呈现之后,当前用户是异步获取的。这意味着容器组件不知道它需要重新执行其 componentDidMount
函数中的代码,该代码将更新要发送到 SitesTable
的数据。我认为当容器组件之一的道具(用户)发生更改时,我需要重新渲染容器组件。我该如何正确地做到这一点?
class SitesTableContainer extends React.Component {
static get propTypes() {
return {
sites: React.PropTypes.object,
user: React.PropTypes.object,
isManager: React.PropTypes.boolean
}
}
componentDidMount() {
if (this.props.isManager) {
this.props.dispatch(actions.fetchAllSites())
} else {
const currentUserId = this.props.user.get('id')
this.props.dispatch(actions.fetchUsersSites(currentUserId))
}
}
render() {
return <SitesTable sites={this.props.sites}/>
}
}
function mapStateToProps(state) {
const user = userUtils.getCurrentUser(state)
return {
sites: state.get('sites'),
user,
isManager: userUtils.isManager(user)
}
}
export default connect(mapStateToProps)(SitesTableContainer);
componentDidMount
中调度的操作将更改应用程序状态中的 sites
节点,该节点被传递到 SitesTable
。 SitesStable 的 sites
节点将发生变化。
您必须在 componentDidUpdate
方法中添加条件。
该示例使用 fast-deep-equal
比较对象。
import equal from 'fast-deep-equal'
...
constructor(){
this.updateUser = this.updateUser.bind(this);
}
componentDidMount() {
this.updateUser();
}
componentDidUpdate(prevProps) {
if(!equal(this.props.user, prevProps.user)) // Check if it's a new user, you can also use some unique property, like the ID (this.props.user.id !== prevProps.user.id)
{
this.updateUser();
}
}
updateUser() {
if (this.props.isManager) {
this.props.dispatch(actions.fetchAllSites())
} else {
const currentUserId = this.props.user.get('id')
this.props.dispatch(actions.fetchUsersSites(currentUserId))
}
}
使用 Hooks (React 16.8.0+)
import React, { useEffect } from 'react';
const SitesTableContainer = ({
user,
isManager,
dispatch,
sites,
}) => {
useEffect(() => {
if(isManager) {
dispatch(actions.fetchAllSites())
} else {
const currentUserId = user.get('id')
dispatch(actions.fetchUsersSites(currentUserId))
}
}, [user]);
return (
return <SitesTable sites={sites}/>
)
}
如果您要比较的道具是对象或数组,则应使用 useDeepCompareEffect
而不是 useEffect
。
由于存在错误和不一致,componentWillReceiveProps()
将来会被弃用。在 props 更改时重新渲染组件的另一种解决方案是使用 componentDidUpdate()
和 shouldComponentUpdate()
。
每当组件更新并且如果 shouldComponentUpdate()
返回 true(如果未定义 shouldComponentUpdate()
,它默认返回 true
),就会调用 componentDidUpdate()
。
shouldComponentUpdate(nextProps){
return nextProps.changedProp !== this.state.changedProp;
}
componentDidUpdate(props){
// Desired operations: ex setting state
}
通过在其中包含条件语句,仅使用 componentDidUpdate()
方法即可完成相同的行为。
componentDidUpdate(prevProps){
if(prevProps.changedProp !== this.props.changedProp){
this.setState({
changedProp: this.props.changedProp
});
}
}
如果尝试在没有条件或未定义 shouldComponentUpdate()
的情况下设置状态,组件将无限重新渲染
componentWillReceiveProps
即将被弃用并建议不要使用,因此需要对此答案进行投票(至少目前如此)。
您可以使用随道具更改的 KEY
唯一键(数据组合),并且该组件将使用更新的道具重新呈现。
componentWillReceiveProps(nextProps) { // your code here}
我认为这是您需要的活动。 componentWillReceiveProps
每当您的组件通过 props 接收到东西时触发。从那里您可以进行检查,然后做任何您想做的事情。
componentWillReceiveProps
已弃用*
我建议您看看我的这个 answer,看看它是否与您正在做的事情相关。如果我了解您的真正问题,那是您只是没有正确使用异步操作并更新了 redux“商店”,这将使用它的新道具自动更新您的组件。
您的代码的这一部分:
componentDidMount() {
if (this.props.isManager) {
this.props.dispatch(actions.fetchAllSites())
} else {
const currentUserId = this.props.user.get('id')
this.props.dispatch(actions.fetchUsersSites(currentUserId))
}
}
不应在组件中触发,应在执行第一个请求后处理。
查看 redux-thunk 中的这个示例:
function makeASandwichWithSecretSauce(forPerson) {
// Invert control!
// Return a function that accepts `dispatch` so we can dispatch later.
// Thunk middleware knows how to turn thunk async actions into actions.
return function (dispatch) {
return fetchSecretSauce().then(
sauce => dispatch(makeASandwich(forPerson, sauce)),
error => dispatch(apologize('The Sandwich Shop', forPerson, error))
);
};
}
您不一定必须使用 redux-thunk,但它会帮助您推理此类场景并编写匹配的代码。
makeASandwichWithSecretSauce
?
一个友好的使用方法如下,一旦 prop 更新它会自动重新渲染组件:
render {
let textWhenComponentUpdate = this.props.text
return (
<View>
<Text>{textWhenComponentUpdate}</Text>
</View>
)
}
您可以在要重新呈现的组件中使用 getDerivedStateFromProps()
生命周期方法,以根据传递给组件的 props
的传入更改设置其状态。更新状态将导致重新渲染。它是这样工作的:
static getDerivedStateFromProps(nextProps, prevState) {
return { myStateProperty: nextProps.myProp};
}
这会将组件状态中 myStateProperty
的值设置为 myProp
的值,并且组件将重新渲染。
确保您了解使用这种方法的潜在影响。特别是,您需要避免无意中覆盖组件的状态,因为父组件中的 props
已意外更新。如果需要,您可以通过将现有状态(由 prevState
表示)与任何传入的 props
值进行比较来执行检查逻辑。
仅在 props
中的值是状态值的真实来源的情况下,才使用更新的道具来更新状态。如果是这种情况,可能还有一种更简单的方法可以实现您的需求。参见 - You Probably Don't Need Derived State – React Blog。
不定期副业成功案例分享
user
更改时卸载并重新安装吗?这有多贵?