React react-redux props或state更新视图无法重新渲染问题
阅读原文时间:2023年07月11日阅读:1

记录学习React时自己是如何挖坑把自己埋了的过程:children以及其它props被修改时相关组件无法重新渲染(做了两天)

父组件代码:

class UserHome extends Component<Props, State> implements IUserHome {

  public name: string | undefined;

  public readonly state: State = initialState;

  public handlerClick() {
    store.dispatch(sendAction());
  }

  /**
   * DOM挂载完成后执行
   */
  public componentDidMount() {
    store.subscribe(this.subscribe)
  }

  public render() {
    return (
      <HomeBackground url={BackgroundImg}>
        <HomeScreenHeightBox width={1400} background='rgba(246, 248, 249, .92)'>
          <button onClick={() => {
            this.props.setCount(10)
            // console.log(this.state.count)
          }}> 点我</button>
          <HomeNavigationBar height={this.state.count} />
        </HomeScreenHeightBox>
      </HomeBackground>
    )
  }
}

const mapDispatchToProps = (dispatch: Function): mapDispatchToPropsInterface => {
  return {
    sendAction() {
      dispatch({
        type: 'send_action',
        value: "UpYou of blog"
      })
    },
    setCount(sun) {
      dispatch({
        type: 'set_count',
        count: sun
      })
    }
  }
}

const mapStateToProps = (state: StateInferface) => {
  // console.log(state)
  return state;
}

export default connect(mapStateToProps, mapDispatchToProps)(UserHome)

readux层

const initialState: StateInferface = {
  value: "HELLO WORLD",
  count: 50,
  height: 50
}

const reducer = (state = initialState, action: ActionInterface): any => {
  switch (action.type) {
    case "send_action":
      return Object.assign({ ...state }, action);
    case "set_count":
      return Object.assign({ ...state }, {  count: state.count + 10});
    default:
      return state;
  }
}

export default reducer;

现需求是点击“点我”按钮改变HomeNavigationBar组件height属性,HomeNavigationBar代码(这个组件实际上是将height再传给另一个容器组件NavigationBar,一下省略了中间调用代码):

/**
 * 首页导航栏容器
 */
export default class HomeNavigationBar extends PureComponent<Props, object> implements IHomeNavigationBar {

  // 设置默认Props
  static defaultProps = {
    height: 50,
    backColor: "#3a3f51"
  }

  private height?: number = this.props.height; // 导航栏高度
  private backColor?: string = this.props.backColor; // 背景颜色
  private children?: ReactNode = this.props.children; // 插槽

  render() {
    const homeNavigationBarStyles = {
      height: `${this.height}px`,
      backgroundColor: `${this.backColor}`
    }
    return (
      <div id='HomeNavigationBar' style={homeNavigationBarStyles}>
        {this.props.height}
        <div className="flex-1">
          {this.children}
        </div>
      </div>
    );
  }
}

NavigationBar中有几段代码导致无法动态改变、重新渲染组件

为了方便直接将props中的值给到height字段,来简单验证一下图中圈起部分代码的可行性:

上图证明无法对基础数据类型的数据进行修改,而是直接将当前变量中的内存地址替换:

let a = 0x213; // 例如等于3
a = 2;// 0x645 改变a的值,实际上改变的是内存地址

所以当props改变时height数据没变化就是这个原因,需要将style中的this.height改为this.props.height,声明的其它变量作废…

由于react中state或props改变时就会触发render方法重新渲染DOM,可以在render中定义height等字段const { children, height, backColor } = this.props;

render() {
    const { children, height, backColor } = this.props;
    const homeNavigationBarStyles = {
      height: `${height}px`,
      backgroundColor: `${backColor}`
    }
    return (
      <div id='HomeNavigationBar' style={homeNavigationBarStyles}>
        <div className="flex-1">
          {children}
        </div>
      </div>
    );
  }