【问题标题】:Why does set state not work within a subscription to an observable?为什么 set state 在订阅 observable 时不起作用?
【发布时间】:2020-10-06 12:09:41
【问题描述】:

下面的代码有一个函数 displayQuotes,它导入一个“下一个”是引号的可观察对象。对于每个新报价,我想使用反应挂钩更新报价的状态。我创建了一个自定义钩子,它接收一个可观察对象,订阅它,并使用每个新值设置状态。我发现,尽管我记录了所有新传入的报价,但似乎我的 setState 在第一次之后就再也没有被调用过。关于为什么会发生这种行为的任何建议?

代码:

const UseCustomHookForObservable = (observable, setState) => {
  useEffect(() => {
    let subscription=observable.subscribe((value) => {
      setState(value);
    });

    return () => subscription.unsubscribe();
  }, [observable, setState]);
};

function DisplayQuotes() {
  const [storedQuotes, setQuotes] = useState({});
  UseCustomHookForObservable(SymbolsObservable, setQuotes);

  return (
    <div>
      <QuotesTable values={storedQuotes} />
    </div>
  );
}

对我来说更奇怪的是以下确实有效:

function DisplayQuotes() {
  return (
    <div>
      <RenderSubscribedValues
        observable={SymbolsObservable}
        component={QuotesTable}
      />
    </div>
  );

class RenderSubscribedValues extends React.Component {
  constructor(props) {
    super(props);
    this.observable = props.observable;
    this.component = props.component;
    this.state = { storedValues: {} };
  }
  componentDidMount() {
    this.subscription = this.observable.subscribe((value) =>
      this.setState({ storedValues: value })
    );
  }
  componentWillUnmount() {
    this.subscription.unsubscribe();
  }
  render() {
    const Component = this.component;
    return (
      <div>
        <Component values={this.state.storedValues} />
      </div>
    );
  }
}
}

我一直认为 useEffect 及其 return 语句实际上与 componentDidMount 和 componentWillUnmount 是一回事?

【问题讨论】:

    标签: reactjs rxjs react-hooks


    【解决方案1】:

    您的状态没有更新,因为 UseCustomHookForObservable 中的 useEffect 只运行了一次。因为钩子只被调用一次,所以SymbolsObservable 不会在您的自定义钩子中更新,从而阻止您的useEffect 再次运行。

    像下面那样做。

    const useCustomHookForObservable = (initialObservable) => {
      const [storedQuotes, setQuotes] = useState({});
      const [observable, setObservable] = useState(initialObservable);
      useEffect(() => {
        observable.subscribe((value) => {
          setQuotes(value);
        });
    
        return () => observable.unsubscribe();
      }, [observable]);
      return {storedQuotes, setObservable}
    };
    
    function DisplayQuotes() {
    
      const {storedQuotes, setObservable} =  useCustomHookForObservable(SymbolsObservable);
    
      useEffect(() => {setObservable(SymbolsObservable)}, [SymbolsObservable])
    
      return (
        <div>
          <QuotesTable values={storedQuotes} />
        </div>
      );
    }
    

    我已经公开了一个 setter 函数,它可以确保您的 useEffect 运行次数与 SymbolsObservable 更新次数一样多。

    这种方式是做正确的更好的方式。 它从 react 组件中提取了你的有状态逻辑,并使它看起来更干净。

    【讨论】:

    • 虽然这绝对是一种更简洁的方法(我不相信您打算在 displayFunction 中传递 setQuotes),但它没有提供解决方案。我仍在记录所有传入的报价,但状态从未改变
    • 我已经更新了我的答案并进行了一些更改并添加了解释,如果它有帮助或者您需要更多解释,请告诉我。
    • 您似乎更改了建议。让我试试……
    • 没有这样做:(。在所有新引号日志中仍然有相同的行为,但没有设置状态。更有趣的是,如果我将它设置为一个类扩展组件,并放入componentDidMount 中的逻辑并使用 this.setState(..),一切正常
    • 你能确定你的自定义钩子中的 useEffect 是否正在运行吗?使用调试器或日志。还有 observable 的值。
    【解决方案2】:

    抱歉,这可能晚了,但它可能会帮助任何人结束这里。

    改变你的'setState(value);'到 'setState([...value]);'如果它是一个数组,或者 'setState({...value});'如果是 obj。

    【讨论】:

      猜你喜欢
      • 2017-11-18
      • 2019-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多