【问题标题】:component not re-rendering after redux state changeredux 状态更改后组件不重新渲染
【发布时间】:2019-08-30 11:49:43
【问题描述】:

我有一个导航组件,它的颜色取决于 redux 状态哈希。

我在另一个组件中有这个导航组件,我试图在其中实现链接的颜色及其状态根据我单击的内容而变化的效果。

一切都已连接,我可以在 redux-logger 中看到状态变化,但导航组件不会重新渲染。但是,当我将鼠标悬停在链接上时,它会反映更改。

redux 状态是这样的

  navProperties: {
    bold: "black",
    dim: "gray",
    social: "#724474",
    socialText: "white",
    socialHover: "#dbb7c8"
  }

第一次渲染父组件和导航栏时,changeNavProperties(propertiesHash) 起作用,颜色反映了我在componentWillMount()中设置的内容;

  componentWillMount() {
    this.props.selectNavLink(this.props.match.url);
    this.props.changeNavProperties({
      bold: "black",
      dim: "gray",
      social: "#4d6cb7",
      socialText: "white",
      socialHover: "#738dce"
    });
  }

这是我的动作和减速器

export default function(state = {}, action) {
  switch (action.type) {
    case "CHANGE_NAV_PROPERTIES":
      return action.payload;
    default:
      return state;
  }
}
export function changeNavProperties(newProperties) {
  return {
    type: "CHANGE_NAV_PROPERTIES",
    payload: newProperties
  };
}

这是我在父组件中调用的函数。单击一个 li 会更改其中一个导航栏项的颜色

class Skills extends Component {

  ...

  handleClick = e => {
    if (e.target.innerHTML === "HTML") {
      this.props.changeNavProperties({
        bold: "white",
        dim: "#333333",
        social: "#e44d26",
        socialText: "white",
        socialHover: "#738dce"
      });
    };
  }

  render() {
    return (
      <div className="skills-container">
        <Navbar />
        <ul>
            <li onClick={this.handleClick}>HTML</li>

        ...

      </div>
    );
  }
}
  ...

  function mapStateToProps(state) {
    return {
      selectedNavLink: state.selectedNavLink
    };
  }

  function mapDispatchToProps(dispatch) {
    return bindActionCreators({ selectNavLink, changeNavProperties }, 
  dispatch);
  }

  export default connect(
    mapStateToProps,
    mapDispatchToProps
  )(Skills);


导航栏组件

class Navbar extends Component {

  componentDidMount() {
    this.setNavProperties();
  }

  setNavProperties = () => {
    document.querySelector(
      ".logo h1"
    ).style.color = this.props.navProperties.bold;
    document.querySelector(
      ".navigation hr"
    ).style.borderColor = this.props.navProperties.bold;
    let navLinks = document.querySelectorAll(".navigation a");

    navLinks.forEach(link => {
      link.style.color = this.props.navProperties.dim;
      if (link.getAttribute("href") === this.props.selectedNavLink) {
        link.parentElement.classList.remove("inactive-link");
        link.parentElement.classList.add("active-link");
        link.style.color = this.props.navProperties.bold;
      }
    });

    let socialMedia = document.querySelectorAll(".social-media i");
    socialMedia.forEach(icon => {
      icon.style.background = this.props.navProperties.social;
      icon.style.color = this.props.navProperties.socialText;
    });
  };


  ...


  function mapStateToProps(state) {
    return {
      selectedNavLink: state.selectedNavLink,
      navProperties: state.navProperties
    }; 
  }

  function mapDispatchToProps(dispatch) {
    return bindActionCreators({ selectNavLink }, dispatch);
  }

  export default connect(
    mapStateToProps,
    mapDispatchToProps
  )(Navbar);
}

【问题讨论】:

  • 请提供有关您的容器的更多信息
  • 请展示您如何通过 connect 和 mapStateToProps() 将组件连接到商店
  • 您需要更新 redux 中的状态,但您没有这样做,而是在收到时返回有效负载
  • @JasperBernales 我更新了代码
  • @AlexanderStaroselsky 我更新了代码

标签: reactjs redux


【解决方案1】:

您需要更新 redux 中的状态,但您没有这样做,而是在收到时返回有效负载

export default function(state = {}, action) {
  switch (action.type) {
    case "CHANGE_NAV_PROPERTIES":
      /*update the state so that you can re-render data in UI*/
      return Object.assign({}, state, {
        selectedNavLink: action.payload
      }); /*do it like the above*/
    default:
      return state;
  }
}

阅读以下内容了解更多详情 - https://redux.js.org/basics/reducers

【讨论】:

    【解决方案2】:

    当您调度 "CHANGE_NAV_PROPERTIES" 操作时,您的有效负载包含导航属性。

    缺少的部分是确保将其正确分配给navProperties

    case "CHANGE_NAV_PROPERTIES":
      return {
        ...state,
        navProperties: action.payload // assign it to navProperties key in store
      };
    

    或使用Object.assign():

    case "CHANGE_NAV_PROPERTIES":
      return Object.assign({}, state, {
        navProperties: action.payload
      });
    

    【讨论】:

    • 导出默认函数(state = {}, action) { switch (action.type) { case CHANGE_NAV_PROPERTIES: return Object.assign({}, state, action.payload);默认:返回状态; } }
    • 不管我做什么,都是一样的。我看到 redux 状态发生了变化,但组件没有立即反映这些变化
    • "no matter what I do, it's the same." - 您评论的 sn-p 不同。它永远不会分配给navProperties
    • @toekneeyou,请仔细查看两个选项。顺便问一下有什么错误?
    • 抱歉,没有错误,哈哈。它像其他人的方法一样更新树,但组件不会立即反映更改,直到我将鼠标悬停在链接上
    【解决方案3】:

    这个

    export default function(state = {}, action) {
      switch (action.type) {
        case "CHANGE_NAV_PROPERTIES":
          return action.payload;
        default:
          return state;
      }
    }
    

    应该是这样的:

    export default function(state = {}, action) {
      switch (action.type) {
        case "CHANGE_NAV_PROPERTIES":
          return { ...state, navProperties: action.payload };
        default:
          return state;
      }
    }
    

    提供上述更改的原因是您的方法覆盖了 redux 存储中的所有内容。简单地说,您通过返回 action.payload 来改变商店。

    请原谅任何错字,我是用手机写的。

    【讨论】:

    • 为什么会这样?
    • 你好,同样的问题,大家的方法更新了redux树,但是组件并没有立即重新渲染。当我将鼠标悬停在导航链接上时,它们会改变
    • 在这种情况下,请使用 codeandbox 或 stackblitz 重现此问题
    猜你喜欢
    • 2020-07-12
    • 2021-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-26
    • 2018-12-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多