React 子组件仅在刷新时更新

Posted

技术标签:

【中文标题】React 子组件仅在刷新时更新【英文标题】:React child component only updates on refresh 【发布时间】:2021-11-14 01:41:51 【问题描述】:

我在 React 中使用函数组件,我有一个名为 'ChallengeItem' 的父组件和一个名为 'ChallengeItem' 的子组件。

'Challenges' 组件调用一个名为 'getAllChallenges' 的操作,该操作从我的数据库中获取所有挑战并通过它们进行映射:

import React,  Fragment, useEffect  from 'react';
import PropTypes from 'prop-types';
import  connect  from 'react-redux';
import  getAllChallenges  from '../../actions/challenge';
import Loading from '../layout/Loading';
import ChallengeItem from './ChallengeItem';

const Challenges = (
  getAllChallenges,
  challenge:  challenges, loading ,
  progress,
) => 
  useEffect(() => 
    getAllChallenges();
  , [getAllChallenges]);

  return loading ? (
    <Loading />
  ) : (
    <Fragment>
      <h1 className='text-center mt-5'>Course Syllabus</h1>
      <div className='row mt-5 mx-5 row-cols-1 row-cols-md-2 row-cols-lg-4 g-4'>
        challenges.map((challenge) => (
          <ChallengeItem key=challenge._id challenge=challenge />
        ))
      </div>
    </Fragment>
  );
;

Challenges.propTypes = 
  getAllChallenges: PropTypes.func.isRequired,
  challenge: PropTypes.object.isRequired,
  progress: PropTypes.object.isRequired,
;

const mapStateToProps = (state) => (
  challenge: state.challenge,
  progress: state.auth.user.progress,
);

export default connect(mapStateToProps,  getAllChallenges )(Challenges);

'ChallengeItem' 组件返回一个动态显示个人挑战信息的 Fragment:

import React,  Fragment  from 'react';
import PropTypes from 'prop-types';
import  connect  from 'react-redux';
import  Link  from 'react-router-dom';

const ChallengeItem = (
  auth,
  user:  progress ,
  challenge:  _id, section_name, section_no, challenge_no, challenge_name ,
) => (
  <Fragment>
    <div className='col'>
      <div className='card challengeCard'>
        <div className='card-body'>
          <h5 className='card-title'>
            Section section_no, Challenge challenge_no
          </h5>
          <p className='card-text'>
            section_name- challenge_name
          </p>
          isChallengeUnlocked(_id, progress) ? (
            <Link
              to=`/challenge/$_id`
              className='btn btn-secondary pinkBtn'
            >
              Unlocked <i className='fas fa-lock-open'></i>
            </Link>
          ) : (
            <button className='btn btn-secondary pinkBtn' disabled>
              Locked <i className='fas fa-lock'></i>
            </button>
          )
        </div>
      </div>
    </div>
  </Fragment>
);

ChallengeItem.propTypes = 
  challenge: PropTypes.object.isRequired,
  auth: PropTypes.object.isRequired,
;

const mapStateToProps = (state) => (
  auth: state.auth,
  user: state.auth.user,
);

export default connect(mapStateToProps)(ChallengeItem);

function isChallengeUnlocked(_id, progress) 
  for (const value of progress) 
    if (value.challenge === _id) 
      return true;
    
  
  return false;

'ChallengeItem' 组件中还有一个函数,它根据用户的进度确定他们是否已解锁特定挑战。

如果他们解锁了挑战,它将显示出来,并且用户可以点击链接导航到该挑战。

如果他们解锁了挑战,则会显示该挑战,但此挑战的按钮将禁用,用户将无法点击它。

我遇到的问题是,当用户新解锁挑战并且用户导航到挑战页面以查看所有锁定/解锁的挑战时,新解锁的挑战在页面上显示为锁定且仅当页面刷新时,新解锁的挑战会显示为解锁状态。

当子组件更新时如何获得重新渲染的挑战?

我在网上搜索了一个答案,似乎很多人都在说为子组件设置一个密钥以便它重新渲染,但我已经在这样做了。我不确定是什么问题,也许这是一个单独的问题。

非常感谢您在此阶段提供的任何帮助,谢谢!

编辑:

// getAllChallenges action
export const getAllChallenges = () => async (dispatch) => 
  try 
    const res = await axios.get(`/api/challenge/all`);

    dispatch(
      type: GET_CHALLENGES,
      payload: res.data,
    );
   catch (err) 
    dispatch(
      type: CHALLENGE_ERROR,
      payload:  msg: err.response.statusText, status: err.response.status ,
    );
  
;
// UPDATE_PROGRESS reducer
case UPDATE_PROGRESS:
      return 
        ...state,
        user: 
          ...state.user,
          progress: payload,
        ,
        loading: false,
      ;

【问题讨论】:

目前,您只能在开头抓取。您需要将进度传递给函数,然后将其添加到依赖数组中。基本上,如果进度更改触发获取。 我尝试将 Challenge 组件中的 useEffect 更改为:useEffect(() => getAllChallenges(); , [progress]);当进度状态发生变化时尝试加载所有挑战,但它仍然给我同样的问题 getAllChallenges 操作看起来如何? 嗨 Seshkebab,我删除了我的答案,对此感到抱歉。我错过了你正在使用 redux。顺便说一句,当您发现挑战已解锁时,您是否可以不发送操作。这将更新存储在 redux 存储中的challenges @merko 我已经更新了我的答案,附带了 getAllChallenges 操作 【参考方案1】:

由于ChallengeItem 是一个 Redux 连接组件,它依赖于 Redux 状态,因此您需要设置 pure: false in the connect() options:

export default connect(mapStateToProps, null, null, pure: false)(ChallengeItem);

【讨论】:

谢谢,我试过了,但对我不起作用

以上是关于React 子组件仅在刷新时更新的主要内容,如果未能解决你的问题,请参考以下文章

react父组件传入的属性没有让子组件收到的prop变化

子组件的动态刷新问题

是否可以仅在 react-router 转换时仅重新安装新的子组件

React Hook - 仅在组件卸载时使用效果,而不是在依赖项更新时使用

React:子组件在提交表单时不会重新呈现

每当我在子组件之间切换时,父组件的 React Router Props 都会刷新