从 firestore 中删除数据时呈现 react-redux 功能组件时出错(useFirestoreConnect)
Error rendering react-redux functional component when data is deleted from firestore (useFirestoreConnect)
我的 ArticleList
组件在我首次加载应用程序时成功地从 firestore 获取并显示用户的文章列表。用户可以点击一个 "Remove Article" 按钮,成功从 firestore 的子集合中移除文章,但会导致 react 组件渲染出错,似乎仍在尝试渲染刚刚移除的文章现在为空。我还能做些什么来让我的 React 组件持续监听 firestore 数据吗?如果可能的话,我想保留它的功能组件并使用 hooks 而不是将其变成 class,但我仍在学习如何使用 React hooks,因此有点挣扎。
ArticleList
分量:
const ArticleList = (props) => {
const firestore = useFirestore();
const userId = props.auth.uid;
useFirestoreConnect([
{
collection: 'users',
doc: userId,
subcollections: [{collection: 'articles'}],
storeAs: userId + '::articles'
}
]);
const myArticles = useSelector(state => state.firestore.data[`${userId}::articles`]);
const dispatch = useDispatch();
const removeArticle = useCallback(
articleId => dispatch(removeArticleFromFirebase({ firestore }, articleId)),
[firestore]
);
if (props.auth.uid) {
return(
<div>
<h3>My Articles</h3>
<p>Currently signed in: {props.auth.email}</p>
<br/>
{myArticles ? (
Object.keys(myArticles).map(articleId => {
let article = myArticles[articleId];
let articleInformation = '';
if (articleId === props.currentPaperId) {
articleInformation =
<div>
<p>{article.year}</p>
<p>{article.description}</p>
<a target="_blank" href={article.downloadUrl}><button className='waves-effect waves-light btn-small'>See article</button></a>
<button className='waves-effect waves-light btn-small' onClick={() => {removeArticle(articleId);}}>Remove from My Articles</button>
</div>;
}
let authorName = '';
if (article.author) {
authorName = ` by ${article.author}`;
}
if (article) {
return <span key={articleId}>
<li onClick={() => {dispatch(selectArticle(articleId));}}>
<em>{article.title}</em>{authorName}
</li>{articleInformation}
</span>;
} else {
return null;
}
})
) : (
<h4>No articles yet</h4>
)
}
</div>
);
} else {
return null;
}
};
const mapStateToProps = (state) => {
return {
currentPaperId: state.currentPaperId,
auth: state.firebase.auth
};
};
export default compose(connect(mapStateToProps))(ArticleList);
以及 removeArticleFromFirebase
操作:
export const removeArticleFromFirebase = ({ firestore }, id) => {
return (dispatch, getState) => {
const userId = getState().firebase.auth.uid;
firestore
.collection('users')
.doc(userId)
.collection('articles')
.doc(id)
.delete()
.then(() => {
console.log('Deleted article from firestore: ', id);
dispatch({ type: 'REMOVE_ARTICLE', id });
})
.catch(err => {
console.log('Error: ', err);
});
};
}
我试过在 ArticleList
中添加 useState
和 useEffect
如下(并尝试让组件的 return 语句映射到 myArticlesState
myArticles
),但没有成功:
const [myArticlesState, setMyArticlesState] = useState(myArticles);
useEffect(() => {
setMyArticlesState(myArticles);
}, [myArticles]);
注意:我 没有 目前在整个应用 state/redux store/props 中根本没有这篇文章列表。这是我接下来要尝试的事情,但我决定先 post 我的问题,以防我只能在此组件中使用挂钩。该应用程序的其他 components/parts 不需要访问此特定列表。
控制台错误:
error image 1
error image 2
Github 回购:https://github.com/jpremmel/yarp2.0
你能告诉我们错误吗?我认为这是关于删除数据后状态不是数组的问题,只需使用这样的空数组初始化状态即可:
Const= [articlesdata,setArticlesData]=useState([])
并保留 useEffect 原样
很难看清发生了什么,但您似乎正试图对一个不存在的对象使用 属性。因此,检查这些属性应该有助于解决这个问题。
您可以尝试将以下代码作为您的 ArticleList 吗?
const ArticleList = (props) => {
const firestore = useFirestore();
const userId = props.auth.uid;
useFirestoreConnect([{
collection: 'users',
doc: userId,
subcollections: [{ collection: 'articles' }],
storeAs: userId + '::articles'
}]);
const myArticles = useSelector(state => state.firestore.data[`${userId}::articles`]);
const dispatch = useDispatch();
const removeArticle = useCallback(articleId => dispatch(removeArticleFromFirebase({ firestore }, articleId)), [firestore]);
if (props.auth.uid) {
return (
<div>
<h3>My Articles</h3>
<p>Currently signed in: {props.auth.email}</p>
<br />
{myArticles ? (
Object.keys(myArticles).map(articleId => {
let article = myArticles[articleId];
let articleInformation = '';
if (article) {
if (
articleId === props.currentPaperId &&
article.hasOwnProperty('year') &&
article.hasOwnProperty('description') &&
article.hasOwnProperty('downloadUrl')
) {
articleInformation =
<div>
<p>{article.year}</p>
<p>{article.description}</p>
<a target="_blank" href={article.downloadUrl}><button className='waves-effect waves-light btn-small'>See article</button></a>
<button className='waves-effect waves-light btn-small' onClick={() => { removeArticle(articleId); }}>Remove from My Articles</button>
</div>;
}
let authorName = '';
if (article.hasOwnProperty('author') && article.author) {
authorName = ` by ${article.author}`;
}
if (article.hasOwnProperty('title') && article.title) {
return <span key={articleId}>
<li onClick={() => { dispatch(selectArticle(articleId)); }}>
<em>{article.title}</em>{authorName}
</li>{articleInformation}
</span>;
} else {
return null;
}
}
})
) : (
<h4>No articles yet</h4>
)
}
</div>
);
} else {
return null;
}
};
const mapStateToProps = (state) => {
return {
currentPaperId: state.currentPaperId,
auth: state.firebase.auth
};
};
export default compose(connect(mapStateToProps))(ArticleList);
我的 ArticleList
组件在我首次加载应用程序时成功地从 firestore 获取并显示用户的文章列表。用户可以点击一个 "Remove Article" 按钮,成功从 firestore 的子集合中移除文章,但会导致 react 组件渲染出错,似乎仍在尝试渲染刚刚移除的文章现在为空。我还能做些什么来让我的 React 组件持续监听 firestore 数据吗?如果可能的话,我想保留它的功能组件并使用 hooks 而不是将其变成 class,但我仍在学习如何使用 React hooks,因此有点挣扎。
ArticleList
分量:
const ArticleList = (props) => {
const firestore = useFirestore();
const userId = props.auth.uid;
useFirestoreConnect([
{
collection: 'users',
doc: userId,
subcollections: [{collection: 'articles'}],
storeAs: userId + '::articles'
}
]);
const myArticles = useSelector(state => state.firestore.data[`${userId}::articles`]);
const dispatch = useDispatch();
const removeArticle = useCallback(
articleId => dispatch(removeArticleFromFirebase({ firestore }, articleId)),
[firestore]
);
if (props.auth.uid) {
return(
<div>
<h3>My Articles</h3>
<p>Currently signed in: {props.auth.email}</p>
<br/>
{myArticles ? (
Object.keys(myArticles).map(articleId => {
let article = myArticles[articleId];
let articleInformation = '';
if (articleId === props.currentPaperId) {
articleInformation =
<div>
<p>{article.year}</p>
<p>{article.description}</p>
<a target="_blank" href={article.downloadUrl}><button className='waves-effect waves-light btn-small'>See article</button></a>
<button className='waves-effect waves-light btn-small' onClick={() => {removeArticle(articleId);}}>Remove from My Articles</button>
</div>;
}
let authorName = '';
if (article.author) {
authorName = ` by ${article.author}`;
}
if (article) {
return <span key={articleId}>
<li onClick={() => {dispatch(selectArticle(articleId));}}>
<em>{article.title}</em>{authorName}
</li>{articleInformation}
</span>;
} else {
return null;
}
})
) : (
<h4>No articles yet</h4>
)
}
</div>
);
} else {
return null;
}
};
const mapStateToProps = (state) => {
return {
currentPaperId: state.currentPaperId,
auth: state.firebase.auth
};
};
export default compose(connect(mapStateToProps))(ArticleList);
以及 removeArticleFromFirebase
操作:
export const removeArticleFromFirebase = ({ firestore }, id) => {
return (dispatch, getState) => {
const userId = getState().firebase.auth.uid;
firestore
.collection('users')
.doc(userId)
.collection('articles')
.doc(id)
.delete()
.then(() => {
console.log('Deleted article from firestore: ', id);
dispatch({ type: 'REMOVE_ARTICLE', id });
})
.catch(err => {
console.log('Error: ', err);
});
};
}
我试过在 ArticleList
中添加 useState
和 useEffect
如下(并尝试让组件的 return 语句映射到 myArticlesState
myArticles
),但没有成功:
const [myArticlesState, setMyArticlesState] = useState(myArticles);
useEffect(() => {
setMyArticlesState(myArticles);
}, [myArticles]);
注意:我 没有 目前在整个应用 state/redux store/props 中根本没有这篇文章列表。这是我接下来要尝试的事情,但我决定先 post 我的问题,以防我只能在此组件中使用挂钩。该应用程序的其他 components/parts 不需要访问此特定列表。
控制台错误: error image 1 error image 2 Github 回购:https://github.com/jpremmel/yarp2.0
你能告诉我们错误吗?我认为这是关于删除数据后状态不是数组的问题,只需使用这样的空数组初始化状态即可:
Const= [articlesdata,setArticlesData]=useState([])
并保留 useEffect 原样
很难看清发生了什么,但您似乎正试图对一个不存在的对象使用 属性。因此,检查这些属性应该有助于解决这个问题。
您可以尝试将以下代码作为您的 ArticleList 吗?
const ArticleList = (props) => {
const firestore = useFirestore();
const userId = props.auth.uid;
useFirestoreConnect([{
collection: 'users',
doc: userId,
subcollections: [{ collection: 'articles' }],
storeAs: userId + '::articles'
}]);
const myArticles = useSelector(state => state.firestore.data[`${userId}::articles`]);
const dispatch = useDispatch();
const removeArticle = useCallback(articleId => dispatch(removeArticleFromFirebase({ firestore }, articleId)), [firestore]);
if (props.auth.uid) {
return (
<div>
<h3>My Articles</h3>
<p>Currently signed in: {props.auth.email}</p>
<br />
{myArticles ? (
Object.keys(myArticles).map(articleId => {
let article = myArticles[articleId];
let articleInformation = '';
if (article) {
if (
articleId === props.currentPaperId &&
article.hasOwnProperty('year') &&
article.hasOwnProperty('description') &&
article.hasOwnProperty('downloadUrl')
) {
articleInformation =
<div>
<p>{article.year}</p>
<p>{article.description}</p>
<a target="_blank" href={article.downloadUrl}><button className='waves-effect waves-light btn-small'>See article</button></a>
<button className='waves-effect waves-light btn-small' onClick={() => { removeArticle(articleId); }}>Remove from My Articles</button>
</div>;
}
let authorName = '';
if (article.hasOwnProperty('author') && article.author) {
authorName = ` by ${article.author}`;
}
if (article.hasOwnProperty('title') && article.title) {
return <span key={articleId}>
<li onClick={() => { dispatch(selectArticle(articleId)); }}>
<em>{article.title}</em>{authorName}
</li>{articleInformation}
</span>;
} else {
return null;
}
}
})
) : (
<h4>No articles yet</h4>
)
}
</div>
);
} else {
return null;
}
};
const mapStateToProps = (state) => {
return {
currentPaperId: state.currentPaperId,
auth: state.firebase.auth
};
};
export default compose(connect(mapStateToProps))(ArticleList);