当 prop 改变时重新渲染 React 组件
Re-render React component when prop changes
我正在尝试将展示组件与容器组件分开。我有一个 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);
componentWillReceiveProps(nextProps) { // your code here}
我认为这就是您需要的活动。 componentWillReceiveProps
每当你的组件通过 props 接收到东西时触发。从那里你可以进行检查,然后做任何你想做的事情。
我建议您看看我的 ,看看它是否与您正在做的事情相关。如果我理解你的真正问题,那就是你没有正确使用你的异步操作并更新 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))
}
}
不应在组件中触发,应在执行第一个请求后处理。
看看这个来自 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,但它会帮助你推理这样的场景并编写代码来匹配。
您必须在 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}/>
)
}
如果你比较的prop是一个对象或者数组,你应该使用useDeepCompareEffect
instead of useEffect
.
由于错误和不一致,componentWillReceiveProps()
将来会被弃用。在 props 更改时重新渲染组件的另一种解决方案是使用 componentDidUpdate()
和 shouldComponentUpdate()
.
每当组件更新时调用 componentDidUpdate()
并且如果 shouldComponentUpdate()
returns 为真(如果未定义 shouldComponentUpdate()
returns 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()
组件将无限重新渲染
您可以使用 KEY
随 props 变化的唯一键(数据的组合),并且该组件将使用更新的 props 重新渲染。
一个友好的使用方法如下,一旦道具更新它会自动重新渲染组件:
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
的值是状态值的真实来源的情况下,才使用更新的 prop 来更新状态。如果是这样的话,可能还有更简单的方法来实现您的需要。参见 - You Probably Don't Need Derived State – React Blog.
我正在尝试将展示组件与容器组件分开。我有一个 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);
componentWillReceiveProps(nextProps) { // your code here}
我认为这就是您需要的活动。 componentWillReceiveProps
每当你的组件通过 props 接收到东西时触发。从那里你可以进行检查,然后做任何你想做的事情。
我建议您看看我的
您的这部分代码:
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,但它会帮助你推理这样的场景并编写代码来匹配。
您必须在 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}/>
)
}
如果你比较的prop是一个对象或者数组,你应该使用useDeepCompareEffect
instead of useEffect
.
componentWillReceiveProps()
将来会被弃用。在 props 更改时重新渲染组件的另一种解决方案是使用 componentDidUpdate()
和 shouldComponentUpdate()
.
componentDidUpdate()
并且如果 shouldComponentUpdate()
returns 为真(如果未定义 shouldComponentUpdate()
returns 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()
组件将无限重新渲染
您可以使用 KEY
随 props 变化的唯一键(数据的组合),并且该组件将使用更新的 props 重新渲染。
一个友好的使用方法如下,一旦道具更新它会自动重新渲染组件:
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
的值是状态值的真实来源的情况下,才使用更新的 prop 来更新状态。如果是这样的话,可能还有更简单的方法来实现您的需要。参见 - You Probably Don't Need Derived State – React Blog.