【问题标题】:Inside Redux's reducer, can I set a variable in the global (module) scope?在 Redux 的 reducer 中,我可以在全局(模块)范围内设置变量吗?
【发布时间】:2020-11-09 18:56:55
【问题描述】:

这是使用 ReactJS、Redux 和 Redux-thunk。

reducer/get-data.js里面,我可以设置一个

let dataFetchingStartTimestamp;

在全球范围内?我想在全局范围内设置它的原因是函数getData() 以块的形式获取数据,所以第一次,假设它获取前 300 条记录(假设 300 条记录可能需要 10 秒),并且第二次,另外 300 条记录,依此类推,直到达到 6000 条记录。 getData() 将在 AJAX 成功后调用自己。 (promise 的 then 处理程序)。

当用户更改 UI Dropbox 时,现有的 getData() 循环应该停止并使用新值重新启动,并且之前发生的 AJAX 不应该将数据置于 Redux 状态。所以这就是为什么当我们有dataFetchingStartTimestamp时,我们可以设置它,当它是第一次获取数据时,将dataFetchingStartTimestamp设置为Date.now(),然后如果用户更改UI,那么它将是另一个“第一次获取数据”,因此会更改dataFetchingStartTimestamp。所以在这个函数内部或者reducer里面,如果它看到dataFetchingStartTimestamp和之前的值不一样,那么它什么也不做。这意味着,只会执行具有最新dataFetchingStartTimestamp 的操作。

我想传递这个值的方式是当getData()在初始AJAX之后调用自己,将dataFetchingStartTimestamp传递给自己,就像dataFetchingContinuationTimestamp一样,所以这个循环会有一个dataFetchingContinuationTimestamp的值到与全球 dataFetchingStartTimestamp 比较。

reducer 是如何得到这个值的:它会在第一次时,getData() 为 redux 状态调度一个GET_DATA_STARTdataFetchingStartTimestamp 的有效负载。所以在reducer中,case后面的语句可以检查当前全局dataFetchingStartTimestamp是否和Redux状态下的一样。如果它们不同,则根本不要更改状态。

这可以做到吗,或者真的有更好的方法来处理它?我们也可以使用

const dataFetchingStartTimestamp = { value: null };

如果我们只允许设置一个常量,但value 将作为全局值。

另一种方法是使dataFetchingStartTimestamp 成为getData(函数对象)的属性。

也许 dataFetchingStartTimestamp 这里所谓的 global 并不是真正的全局,而是 webpack 打包的作用域的局部变量,或者作为模块内的局部变量?

【问题讨论】:

  • Reducer 是纯函数,所以我想这不是最好的主意...
  • 但是纯函数不能检查状态并采取相应措施吗?例如,即使value: state.value + 1value: state.value % 2 ? "hello" : "world" 也在使用之前的状态
  • 一目了然地解决您的问题,请求取消对您不起作用吗?
  • 请求取消——你的意思是AJAX取消?循环(函数)为 300 条记录生成 1 个 AJAX,当 AJAX 完成时,它会调用自己......所以我想如果 AJAX 可以及时取消,它应该可以工作。但是,如果用户更改下拉框会创建一个事件,并且 AJAX 处理也有一个事件,并且 BOTH 处理程序在同一个事件周期中执行。我认为在reducer中,如果取消AJAX,则会处理有关先前AJAX返回数据的情况......所以我认为唯一的问题是如果两个事件都在同一个事件周期中怎么办......
  • @Patrickkx 顺便说一句,如果reducer 将AJAX 返回的数据设置为状态,那也算是纯函数吗?服务器可以返回任何它想要的东西,所以f(1)可以根据服务器返回13,所以它不是一个纯函数

标签: reactjs redux redux-thunk


【解决方案1】:

我希望我能正确理解这个问题,用户输入会导致异步操作调度,所以如果用户输入搜索输入字符a,然后输入b,那么将触发 2 个搜索:a 和 @987654324 @。如果他们以与用户提供输入不同的顺序解析怎么办? ab 搜索在 1 秒后解析并设置状态。 a 搜索会在 1 秒后解析并覆盖 ab 的结果。您的 UI 现在不同步,在搜索文本中显示 ab,但搜索结果显示为 a(请参阅下面的隐藏示例)

const later = (value) =>
  new Promise((resolve) =>
    setTimeout(
      () => resolve(value),
      value.length === 1 ? 2000 : 1000
    )
  );
const asyncFunction = (setter, value) => {
  console.log('starting async with value:', value);
  later(value).then((value) => {
    console.log('resolved with value:', value);
    setter(value);
  });
};
const App = () => {
  const [result, setResult] = React.useState('');
  const onChange = ({ target: { value } }) => {
    asyncFunction(setResult, value);
  };
  return (
    <div>
      <input type="text" onChange={onChange} />
      <h4>Result:{result}</h4>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

以下是解决此问题的方法:

const later = (value) =>
  new Promise((resolve) =>
    setTimeout(
      () => resolve(value),
      value.length === 1 ? 2000 : 1000
    )
  );
const REPLACED = { message: 'REPLACED' };
const resolveLast = (fn) => {
  const check = {};
  return (...args) => {
    const current = {};
    check.current = current;
    //You could make check.current Data.now() but
    //  object reference is guaranteed to be unique
    return Promise.resolve(fn(...args)).then((resolve) =>
      check.current === current
        ? resolve
        : Promise.reject(REPLACED)
    );
  };
};
const lastLater = resolveLast(later);

const asyncFunction = (setter, value) => {
  console.log('starting async with value:', value);
  lastLater(value)
    .then((value) => {
      console.log('resolved with value:', value);
      setter(value);
    })
    .catch((err) =>
      err === REPLACED
        ? console.log(
            `request for ${value} replaced with newer request`
          )
        : Promise.reject(err)
    );
};
const App = () => {
  const [result, setResult] = React.useState('');
  const onChange = ({ target: { value } }) => {
    asyncFunction(setResult, value);
  };
  return (
    <div>
      <input type="text" onChange={onChange} />
      <h4>Result:{result}</h4>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

【讨论】:

    猜你喜欢
    • 2012-10-28
    • 2015-09-20
    • 1970-01-01
    • 2015-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-13
    相关资源
    最近更新 更多