【问题标题】:reset component's internal state on route change在路由更改时重置组件的内部状态
【发布时间】:2018-07-10 03:31:09
【问题描述】:

我正在使用 react-router-v4 和 react 16。

当用户转到不同的路线或返回相同的路线时,我想重置组件的内部状态。路由更改应该破坏组件的内部状态,但它不会。而且我什至找不到在路由更改时通知组件的方法,因为它是嵌套组件而不是Route 组件的直接渲染。请帮忙。

这是代码或live codepen example --

const initialProductNames = {
    names: [
        { "web applications": 1 },
        { "user interfaces": 0 },
        { "landing pages": 0 },
        { "corporate websites": 0 }
    ]
};

export class ProductNames extends React.Component {

state = {
    ...initialProductNames
};

animProductNames = () => {
    const newArray = [...this.state.names];
    let key = Object.keys(newArray[this.count])[0];
    newArray[this.count][key] = 0;

    setTimeout(() => {
        let count = this.count + 1;

        if (this.count + 1 === this.state.names.length) {
            this.count = 0;
            count = 0;
        } else {
            this.count++;
        }

        key = Object.keys(newArray[count])[0];
        newArray[count][key] = 1;
        this.setState({ names: newArray });
    }, 300);
};

count = 0;

componentDidMount() {
    this.interval = setInterval(() => {
        this.animProductNames();
    }, 2000);
}

componentWillUnmount() {
    clearInterval(this.interval);
}

componentWillReceiveProps(nextProps) {
    console.log(nextProps.match);
    if (this.props.match.path !== nextProps.match.path) {
        this.setState({ ...initialProductNames });
        this.count = 0;
    }
}

render() {
    return (
        <section className="home_products">
            <div className="product_names_container">
                I design & build <br />
                {this.createProductNames()}
            </div>
        </section>
    );
}

createProductNames = () => {
    return this.state.names.map(nameObj => {
        const [name] = Object.keys(nameObj);
        return (
            <span
                key={name}
                style={{ opacity: nameObj[name] }}
                className="product_names_anim">
                {name}
            </span>
        );
    });
};
}

【问题讨论】:

  • 能否提供您的路由代码
  • 是的,为什么不呢。但这没有什么问题
  • 我只是想你可以为位置设置一些全局状态,而在路由的onenter钩子中我们可以修改该状态并可以在组件中使用
  • react-router 的路由改变会破坏组件状态吗?
  • 如果路由更改没有重置组件的内部状态,那么这是 react-router 的默认行为,在这种情况下,我们应该找到一种方法在路由更改时通知组件

标签: reactjs react-router react-router-v4 react-router-dom


【解决方案1】:

我得到了解决方案。我不明白为什么状态为property initializer 在重新安装时不会重置/初始化。我认为它只初始化一次,而不是每次路由更改] -

我想知道如何在路由更改时重置组件的状态。但事实证明,您不必这样做。每个路由都呈现一个特定的组件。当路由更改时,所有其他组件都将被卸载,并且这些组件的所有状态也会被破坏。 但是请看我的代码。我使用 es7+ property initializer 来声明 state,count 。这就是当组件在路由更改时重新挂载时状态没有重新设置/初始化的原因。

为了解决这个问题,我所做的只是把 state,initialProductNames,count;所有这些都进入constructor。现在它运行良好。

现在每次挂载和重新挂载都是新状态!

【讨论】:

  • 嗨,我认为问题不在于属性初始化程序。路由更改后它不起作用的问题可能是因为您在类之外定义了 initialProductNames 这使其成为一个全局 javascript 变量,该变量将被您在组件中执行的任何操作所改变。
  • 不。我使用扩展运算符复制了 state 中的 initialProductNames 数组。所以没有机会改变常数。
  • 嘿,如果可以的话,请看我的回答。我发送它是因为我的一位同事遇到了这个答案,并假设每次重新安装时都不会重新创建状态。在我的回答中,我表明该状态已重新创建。如果我能在这一点上正确回答或更正您的文字,我将不胜感激。
  • 这样,我希望其他人不会像我的同事那样遇到问题(在展示了上述事实后,我们设法纠正了这一点)。
  • 啊,另外,请记住扩展运算符是浅拷贝,而不是深拷贝。
【解决方案2】:

您可以在路由更改上使用监听器作为this previous question 上的示例,您可以在其中添加一个函数来更新主状态。

  componentDidUpdate(prevProps) {
    if (this.props.location !== prevProps.location) {
      this.onRouteChanged();
    }
  }

  onRouteChanged() {
    console.log("ROUTE CHANGED");
  }

【讨论】:

  • 我想你忘了你不能更新未安装的组件。一旦路线改变,你就不能使用 setState
  • 你会如何用钩子来做到这一点?
【解决方案3】:

问题不在于状态,而在于初始产品名称。属性初始化器是一种糖语法,实际上它与创建构造函数并将代码移动到构造函数中相同。问题出在initialProductNames,它是在组件外创建的,即整个系统只创建一次。

要为ProductNames 的任何实例创建一个新的initialProductNames,请执行以下操作:

export class ProductNames extends React.Component {

  initialProductNames = {
    names: [
        { "web applications": 1 },
        { "user interfaces": 0 },
        { "landing pages": 0 },
        { "corporate websites": 0 }
    ]
  };

  state = {
    ...this.initialProductNames
  };

  // more code

  componentWillReceiveProps(nextProps) {
    console.log(nextProps.match);
    if (this.props.match.path !== nextProps.match.path) {
        this.setState({ ...this.initialProductNames });
        this.count = 0;
    }
  }

这是一个示例,显示每次重新挂载时总是重新创建 statehttps://codesandbox.io/s/o7kpy792pq

class Hash {
  constructor() {
    console.log("Hash#constructor");
  }
}

class Child extends React.Component {
  state = {
    value: new Hash()
  };

  render() {
    return "Any";
  }
}

class App extends React.Component {
  state = {
    show: true
  };
  render() {
    return (
      <div className="App">
        <button
          type="button"
          onClick={() =>
            this.setState({
              show: !this.state.show
            })
          }
        >
          Toggle
        </button>
        {this.state.show && <Child />}
      </div>
    );
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-29
    • 1970-01-01
    • 2018-01-05
    • 1970-01-01
    • 2018-09-04
    • 1970-01-01
    • 2019-08-10
    相关资源
    最近更新 更多