以下代码似乎有些出入,有时可以工作。像它那样工作将呈现数据列表,而不像我那样遇到forEach错误,因为this.props.getPosts();
尚未加载。
我需要一种方法来告诉反应以获取this.props.getPosts()
然后为每个循环执行操作,而if
语句则不会。我需要使动作异步。诸如等待获取之类的东西。不确定如何在操作方法中进行操作。
我也遇到了这个错误,我想如果我使我的动作getPosts异步,它将解决这个错误。
index.js:1446警告:无法在服务器上执行React状态更新 未安装的组件。这是空操作,但表示内存泄漏 在您的应用程序中。要修复,请取消所有订阅并异步 componentWillUnmount方法中的任务。
这是我目前拥有的
App.js
const styles = {
card: {
minWidth: 275,
margin:'40px 0px',
},
p:{
margin:'20px 0px',
letterSpacing: '2.7px',
fontSize:'0.8em',
fontStyle: 'italic'
},
h:{
letterSpacing: '5px'
}
};
const equalArrays = (arr1, arr2) => {
if(arr1.length !== arr2.length)
return false;
for(var i = arr1.length; i--;) {
if(arr1[i] !== arr2[i])
return false;
}
return true;
}
class App extends Component{
constructor(props){
super(props)
this.state = {
username:"",
loading: true,
posts:[]
}
}
componentDidUpdate(prevProps) {
const prevMyPosts = prevProps.myPosts;
const myPosts = this.props.myPosts;
if (!equalArrays(prevMyPosts, myPosts)) {
this.setState({ posts: myPosts })
}
}
componentDidMount(){
if(this.props.userId){
const collection = fire.collection('users');
collection.get().then(snapshot => {
snapshot.forEach(doc => {
this.setState({
username: doc.data().username,
loading:false
})
});
});
}
this.props.getPosts();
}
render(){
if (!this.props.userId) return <Redirect to='/' />
const { loading, posts } = this.state;
if(loading){
return(
<div className="loader"></div>
)
}
return(
<div className="container">
<div className="row">
<div className="col-md-6 mt-3">
<h1>Welcome {this.state.username.toLowerCase()}</h1>
{posts.map((post, key)=> {
return(
<Card key={key} style={styles.card}>
<CardContent>
<Typography variant="h4" component="h2" style={styles.h}>
{post.description}
</Typography>
<Typography component="p" style={styles.p}>
by: {post.username}
</Typography>
<Typography component="p">
by: {moment(post.createdAt.toDate()).calendar()}
</Typography>
</CardContent>
</Card>
);
})}
</div>
</div>
</div>
);
}
}
const mapStateToProps = (state) => ({
user: state.auths.user,
userId: state.auths.userId,
myPosts: state.auths.myPosts
})
const mapDispatchToProps = (dispatch) => ({
getPosts: () => dispatch(getPosts())
})
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App));
Actions.js (我想使该操作异步,不确定如何操作)
const _getPosts = (posts) => ({
type: 'GET_POSTS',
posts
})
export const getPosts = () => { return(dispatch) =>{
return fire.collection('posts').get().then(snapshot => {
const posts = [];
snapshot.forEach(item => {
posts.push(item.data());
});
// console.log(posts)
dispatch(_getPosts(posts));
})
}
}
Reducers.js (存储myPosts数据的地方)
import { SET_USER} from '../actions/';
const initialState = {
authError: null,
isAuthenticated: false,
userId: null,
user: {},
myPosts:[]
}
export default (state = initialState, action) => {
switch (action.type) {
case SET_USER:
return ({
...state
userId: action.payload.uid || null,
// user:action.payload,
isAuthenticated: true
})
case 'LOGOUT_SUCCESS':
console.log('signout success')
return ({
...state,
userId: null,
isAuthenticated: false
})
case 'GET_POSTS':
return ({
...state,
myPosts: action.posts
})
case 'CREATE_POST':
console.log('created post', action.post)
return state;
case 'CREATE_POST_ERROR':
console.log('create post error', action.err)
return state;
case 'SIGNUP_SUCCESS':
return ({
...state,
authError: null
})
case 'SIGNUP_ERROR':
console.log('signup error')
return ({
...state,
authError: action.err.message
})
case 'SIGNIN_SUCCESS':
console.log('signin success')
return ({
...state,
authError: null
})
case 'SIGNIN_ERROR':
console.log('signin error')
return ({
...state,
authError: action.err.message
})
default:
return state
}
}
答案 0 :(得分:0)
使redux动作异步不会解决您的问题,最终将冻结UI。相反,不要使用componentWillMount
,而是在getPosts
中调用componentDidMount
并使用componentDidUpdate
来更新状态。假设您的组件已连接到redux存储,则可以执行以下操作:
const equalArrays = (arr1, arr2) => {
if(arr1.length !== arr2.length)
return false;
for(var i = arr1.length; i--;) {
if(arr1[i] !== arr2[i])
return false;
}
return true;
}
class YourComponent extends React.Component {
constructor(props){
super(props)
// this attr will help get rid of memory leak warning.
this._isMounted = false;
this.state = {
username: "",
loading: true,
posts:[]
}
}
componentDidMount() {
this._isMounted = true;
if(this.props.userId) {
const collection = fire.collection('users');
collection.get().then(snapshot => {
// If the component is unmounted, this block
// can still be executed, causing a memory leak
// (hence the warning).
// We can fix it by checking the value of `this._isMounted`.
if (!this._isMounted) { return }
snapshot.forEach(doc => {
this.setState({
username: doc.data().username,
loading:false
})
});
});
}
this.props.getPosts();
}
componentWillUnmount() {
this._isMounted = false;
}
componentDidUpdate(prevProps) {
const prevMyPosts = prevProps.myPosts;
const myPosts = this.props.myPosts;
if (prevMyPosts !== undefined && !equalArrays(prevMyPosts, myPosts)) {
this.setState({ posts: myPosts })
}
}
render() { ... }
}
const mapStateToProps = state => ({
myPosts: state.myPosts,
});
const mapDispatchToProps = dispatch => ({
getPosts: () => dispatch(getPosts()),
});
YourComponent = connect(
mapStateToProps,
mapDispatchToProps,
)(YourComponent);
请注意,更新React组件状态的方式是通过setState,而不是直接。
另外,请注意,必须以this.setState
中的条件包装componentDidUpdate
;否则会导致无限循环。更多详细信息here。
以上方法之所以有效,是因为当您传递给道具的道具发生更改时,与Redux连接的组件将重新渲染,从而触发componentDidUpdate
。