我正在尝试将表示组件与容器组件分开。我有一个SitesTable
和一个SitesTableContainer
。容器负责触发redux操作以根据当前用户获取适当的站点。问题是在最初呈现容器组件之后,异步获取当前用户。这意味着容器组件不知道它需要重新执行其componentDidMount
函数中的代码,该函数将更新要发送到SitesTable
的数据。我想我需要在其中一个props(用户)更改时重新呈现容器组件。我该怎么做?
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);
答案 0 :(得分:60)
您必须在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))
}
}
使用挂钩(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
。
答案 1 :(得分:10)
ComponentWillReceiveProps()
将来会被弃用。在道具更改时重新渲染组件的另一种解决方案是使用ComponentDidUpdate()
和ShouldComponentUpdate()
。
ComponentDidUpdate()
,并且如果ShouldComponentUpdate()
返回true(如果未定义ShouldComponentUpdate()
,则默认返回true
)。
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()
的情况下设置状态,则组件将无限地重新渲染
答案 2 :(得分:5)
componentWillReceiveProps(nextProps) { // your code here}
我认为这是你需要的事件。只要您的组件通过道具收到某些内容,就会触发componentWillReceiveProps
。从那里你可以检查然后做你想做的事。
答案 3 :(得分:2)
我建议您查看我的answer,看看它与您正在做的事情是否相关。如果我理解你的真正问题,那就是你没有正确使用你的异步动作并更新redux“store”,它会自动用它的新道具更新你的组件。
您的代码的这一部分:
componentDidMount() {
if (this.props.isManager) {
this.props.dispatch(actions.fetchAllSites())
} else {
const currentUserId = this.props.user.get('id')
this.props.dispatch(actions.fetchUsersSites(currentUserId))
}
}
不应在组件中触发,应在执行第一个请求后处理。
查看此示例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,但它可以帮助您推理类似这样的场景并编写匹配的代码。
答案 4 :(得分:0)
以下一种易于使用的方法,一旦道具更新,它将自动重新渲染组件:
render {
let textWhenComponentUpdate = this.props.text
return (
<View>
<Text>{textWhenComponentUpdate}</Text>
</View>
)
}
答案 5 :(得分:-1)
您可以使用随道具更改的KEY
唯一键(数据组合),并且该组件将随更新的道具重新呈现。