首页 > 解决方案 > 从firestore中删除数据时渲染react-redux功能组件时出错(useFirestoreConnect)

问题描述

当我第一次加载应用程序时,我ArticleList的组件已成功获取并显示来自 firestore 的用户文章列表。用户可以点击“Remove Article”按钮,成功将文章从firestore的子集合中移除,但是却导致react组件渲染出错,似乎还在尝试渲染刚刚移除的文章,现在为空。我还能做些什么来让我的反应组件不断地监听 firestore 数据吗?如果可能的话,我想保留它一个功能组件并使用钩子而不是让它成为一个类,但我仍在学习如何使用反应钩子,因此有点挣扎。

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);
  });
};
}

我尝试在下面添加useState和(并尝试通过而不是通过组件的返回语句映射),但没有成功:useEffectArticleListmyArticlesStatemyArticles

const [myArticlesState, setMyArticlesState] = useState(myArticles);
useEffect(() => {
setMyArticlesState(myArticles);
}, [myArticles]);

注意:我目前在整个应用程序状态/redux store/props 中根本没有这篇文章列表这是我接下来要尝试的事情,但我决定先发布我的问题,以防我可以在这个组件中使用钩子。应用程序的其他组件/部分不需要访问此特定列表。

控制台错误: 错误图像 1 错误图像 2 Github repo:https ://github.com/jpremmel/yarp2.0

标签: reactjsreact-reduxreact-hooksreact-redux-firebaseredux-firestore

解决方案


很难看到发生了什么,但看起来好像您正在尝试在不存在的对象上使用属性。因此,检查这些属性应该有助于解决这个问题。

您可以尝试以下代码作为您的文章列表吗?

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);

推荐阅读