ComponentDidMount 在 redux 状态更新后没有被调用?
ComponentDidMount not getting called after redux state update?
我想我在这里漏掉了一个关于 React 和 Redux 的概念。我正在尝试使用存储在 redux 中的对象,但我遇到了麻烦。
减少:
我有一个操作 fetchItems,它从数据库中获取所有项目。此操作成功。
反应:
我有一个容器 UserProfile,它在 componentDidMount 中调用 fetchItems。
class UserProfile extends Component {
componentWillMount() {
console.log('------------ USER PROFILE -------------------');
}
componentDidMount() {
console.log('[ComponentDidMount]: Items: ', this.props.items);
this.props.fetchItems();
}
render() {
let profile = null;
console.log('[Render]: Items: ', this.props.items);
return <Auxillary>{profile}</Auxillary>;
}
}
const mapStateToProps = state => {
return {
items: state.items.items
};
};
const mapDispatchToProps = dispatch => {
return {
fetchItems: () => dispatch(actions.fetchItems())
};
};
export default connect(mapStateToProps, mapDispatchToProps)(UserProfile);
我看到的问题是 this.props.items 始终为 null(即使 fetchItems 成功)。我可以检测到项目存储在 redux 存储中的唯一方法是使用 componentWillRecieveProps(nextProps)。在这里,我成功地看到了 nextProps 中的项目。我觉得使用 componentWillReceiveProps 可能太 "messy" 了。我想我想问的是,在 React 中处理 redux 状态更新的标准方法是什么?
阿瑟尔
标准做法是在您的构造函数或 componentWillMount() 中调用 this.props.fetchItems()。
componentDidMount 在渲染之后调用,这就是为什么您的项目不渲染的原因 - 它们在初始渲染之后才存在。
周期为:
constructor()
componentWillMount()
(顺便说一句,很快就会弃用:https://medium.com/@baphemot/whats-new-in-react-16-3-d2c9b7b6193b)
render()
=> 第一次渲染(this.props.items
,来自 mapStateToProps 将是未定义的)
componentDidMount()
=> 启动 fetchItems()
=> 更改 redux 状态 => 更改 this.props.items => 启动第二个 render()
其中 this.props.items
将是设置。
所以:
- 你应该有两个
console.log('[Render]: Items: ', this.props.items);
- 当 this.props.items 为 null
时,您应该处理 "loading" 状态
如果第二个 console.log 仍然为空,请尝试在 reducer 中添加日志,在 mapStateToProps 中,...也许它不是 state.items.items ...
在反应中,我们有一种叫做状态的东西。如果组件的状态发生变化,组件将重新渲染。话虽如此,我们可以在 componentWillRecieveProps
中使用 this.setState()
来更新状态,这反过来又会重新渲染组件。所以你的代码看起来像这样,这是在 React 中处理 Redux 级别状态变化的标准方法。
class UserProfile extends Component {
constructor(props) {
super(props);
this.state = {
items: props.items
}
}
componentWillMount() {
console.log('------------ USER PROFILE -------------------');
}
componentWillRecieveProps({ items }) {
this.setState({ items });
}
componentDidMount() {
console.log('[ComponentDidMount]: Items: ', this.state.items);
this.props.fetchItems();
}
render() {
let profile = null;
console.log('[Render]: Items: ', this.state.items);
return <Auxillary>{profile}</Auxillary>;
}
}
const mapStateToProps = state => {
return {
items: state.items.items
};
};
const mapDispatchToProps = dispatch => {
return {
fetchItems: () => dispatch(actions.fetchItems())
};
};
export default connect(mapStateToProps, mapDispatchToProps)(UserProfile);
P.S 仅在 componentWillMount
中进行 API 调用也无济于事,因为 API 调用是异步的,可能需要一些时间来解决并做出反应将完成渲染组件。所以你仍然需要使用 componentWillRecieveProps
您可以通过某些方法解决此问题。
第一次调用 render() 时,它订阅了通过 redux 连接方法在 redux 存储中初始化的初始 props/state。在你的例子中 items 是 null。
总是用一些有意义的数据初始化你的 redux store。
在您的情况下,如果 items 将是数组,您可以使用空数组进行初始化。
当您发送操作时,您的商店将得到更新,并且订阅了 items 的组件将被重新渲染,这样您就不必使用 setState 在 componentWillReceiveProps 里面,你可以避免使用它。
您需要在渲染中处理某些情况,例如,如果数组为空且数据仍在加载,则显示某种加载程序,一旦获取数据,然后显示它。
我想我在这里漏掉了一个关于 React 和 Redux 的概念。我正在尝试使用存储在 redux 中的对象,但我遇到了麻烦。
减少: 我有一个操作 fetchItems,它从数据库中获取所有项目。此操作成功。
反应: 我有一个容器 UserProfile,它在 componentDidMount 中调用 fetchItems。
class UserProfile extends Component {
componentWillMount() {
console.log('------------ USER PROFILE -------------------');
}
componentDidMount() {
console.log('[ComponentDidMount]: Items: ', this.props.items);
this.props.fetchItems();
}
render() {
let profile = null;
console.log('[Render]: Items: ', this.props.items);
return <Auxillary>{profile}</Auxillary>;
}
}
const mapStateToProps = state => {
return {
items: state.items.items
};
};
const mapDispatchToProps = dispatch => {
return {
fetchItems: () => dispatch(actions.fetchItems())
};
};
export default connect(mapStateToProps, mapDispatchToProps)(UserProfile);
我看到的问题是 this.props.items 始终为 null(即使 fetchItems 成功)。我可以检测到项目存储在 redux 存储中的唯一方法是使用 componentWillRecieveProps(nextProps)。在这里,我成功地看到了 nextProps 中的项目。我觉得使用 componentWillReceiveProps 可能太 "messy" 了。我想我想问的是,在 React 中处理 redux 状态更新的标准方法是什么?
阿瑟尔
标准做法是在您的构造函数或 componentWillMount() 中调用 this.props.fetchItems()。
componentDidMount 在渲染之后调用,这就是为什么您的项目不渲染的原因 - 它们在初始渲染之后才存在。
周期为:
constructor()
componentWillMount()
(顺便说一句,很快就会弃用:https://medium.com/@baphemot/whats-new-in-react-16-3-d2c9b7b6193b)render()
=> 第一次渲染(this.props.items
,来自 mapStateToProps 将是未定义的)componentDidMount()
=> 启动fetchItems()
=> 更改 redux 状态 => 更改 this.props.items => 启动第二个render()
其中this.props.items
将是设置。
所以:
- 你应该有两个
console.log('[Render]: Items: ', this.props.items);
- 当 this.props.items 为 null 时,您应该处理 "loading" 状态
如果第二个 console.log 仍然为空,请尝试在 reducer 中添加日志,在 mapStateToProps 中,...也许它不是 state.items.items ...
在反应中,我们有一种叫做状态的东西。如果组件的状态发生变化,组件将重新渲染。话虽如此,我们可以在 componentWillRecieveProps
中使用 this.setState()
来更新状态,这反过来又会重新渲染组件。所以你的代码看起来像这样,这是在 React 中处理 Redux 级别状态变化的标准方法。
class UserProfile extends Component {
constructor(props) {
super(props);
this.state = {
items: props.items
}
}
componentWillMount() {
console.log('------------ USER PROFILE -------------------');
}
componentWillRecieveProps({ items }) {
this.setState({ items });
}
componentDidMount() {
console.log('[ComponentDidMount]: Items: ', this.state.items);
this.props.fetchItems();
}
render() {
let profile = null;
console.log('[Render]: Items: ', this.state.items);
return <Auxillary>{profile}</Auxillary>;
}
}
const mapStateToProps = state => {
return {
items: state.items.items
};
};
const mapDispatchToProps = dispatch => {
return {
fetchItems: () => dispatch(actions.fetchItems())
};
};
export default connect(mapStateToProps, mapDispatchToProps)(UserProfile);
P.S 仅在 componentWillMount
中进行 API 调用也无济于事,因为 API 调用是异步的,可能需要一些时间来解决并做出反应将完成渲染组件。所以你仍然需要使用 componentWillRecieveProps
您可以通过某些方法解决此问题。 第一次调用 render() 时,它订阅了通过 redux 连接方法在 redux 存储中初始化的初始 props/state。在你的例子中 items 是 null。 总是用一些有意义的数据初始化你的 redux store。
在您的情况下,如果 items 将是数组,您可以使用空数组进行初始化。 当您发送操作时,您的商店将得到更新,并且订阅了 items 的组件将被重新渲染,这样您就不必使用 setState 在 componentWillReceiveProps 里面,你可以避免使用它。
您需要在渲染中处理某些情况,例如,如果数组为空且数据仍在加载,则显示某种加载程序,一旦获取数据,然后显示它。