【问题标题】:Node and React are not in syncNode 和 React 不同步
【发布时间】:2018-05-09 02:14:51
【问题描述】:

我能够实现以下目标 -> 当用户单击组件 A 中的特定日期时,数据会被发送到节点(Sails API),在那里完成所有必要的计算,并且在组件 B 呈现正确之前数据已准备好显示。

问题是当用户从组件 B 返回到组件 A 并选择不同的日期时,他/她会得到完全相同的结果(旧值),因为即使将新值发送到后端 API,Node 也是'不使用新值进行重新计算。

只有在手动刷新页面或对服务器进行更改以强制重新计算后,我才能获得正确的结果。

我想我需要提一下,我正在使用 Redux 传递数据,所以问题可能出现在那部分。

我会考虑某种类型的自动刷新、动画加载等。 是的,所以卡住了:/

是否有可能使它们完全同步?

更新 --> 下面是代码:

后台

getDetails: (req, res) => {
    authentication.authenticate().then((auth) => {
      const sheets = google.sheets('v4');
      sheets.spreadsheets.values.get({
        auth: auth,
        spreadsheetId: config.spreadsheetSettings.spreadsheetId, // id of spreadsheet
        range: config.spreadsheetSettings.employeeSheetId, // name of employee spreadsheet and range- get all cells
      }, (err, response) => {
        if (err) {
          res.serverError(err);
          return;
        }
        const rows = response.values; // response-all cells
        const updatedData = employeeService.mapEmployeeSheetToJson(rows);

         // FETCHING THE VALUE FROM REST API
        let myArr = [];

        (function() {

                    axios.get(`http://localhost:1337/api/`)
                    .then(res =>  {
                    let kajmak = res.data.slice(-1)[0]
                    let test = kajmak[Object.keys(kajmak)[0]]
                    myArr.push(test)
                    }).catch(err => console.error(err));
             })();

        // MAPING OVER THE ARRY AND DOING THE LOGIC
        setTimeout(() => {
            myArr.map(xo => {

        const result = [];

    updatedData.forEach(emp => {//  2013     2012  2014
        if (xo > parseInt(moment(emp.startdate).format('YYYYMM'), 10) &&
          (xo < parseInt(moment(emp.enddate).format('YYYYMM'), 10))) {
              result.push(emp);
          }
      });

      // IF THEY STARTED WORKING BEFORE THE SELECTED DATE AND STILL WORKING
    updatedData.forEach(emp => { // 2013   > 2012 & 2013   -
          if (xo > parseInt(moment(emp.startdate).format('YYYYMM'), 10) && 
              ((parseInt(moment(emp.enddate).format('YYYYMM'), 10) == undefined ))) {
                  result.push(emp);
          }
      });

      // IF THEY STARTED WORKIG BEFORE THE SELECTED DATE,
      // BUT STOPPED WORKING BEFORE THE SELECTED DATE
    updatedData.forEach(emp => {  // 2013  <    2014 ||     2013  > 2017
          if (xo < parseInt(moment(emp.startdate).format('YYYYMM'), 10) &&
              (xo > parseInt(moment(emp.startdate).format('YYYYMM'), 10))) {
                  result.pop(emp);
          }
      });

        // Getting the names to use for unique sheet req
        let finalResult = [];
        result.map(x => {
            finalResult.push((x.name + ' ' + x.surname))
        })

        if (rows.length === 0) {
          res.err('No data found.');
        } else {
          res.ok(finalResult);
        }
    }) 
        }, 1000);
    });

}

前端

getEmployeeSalaryData = () => {
            // GETTING THE CLICKED VALUE FROM THE PREVIOUS COMPONENT
            const { year } = this.props.history.location.state.item;
            const { month } = this.props.history.location.state.item;
            const selectedMonth = moment().month(month).format("MM");
            const finalSelect = parseInt(year + selectedMonth, 10);
            const { employees } = this.props;
            // I'M RECIEVING THIS AS PROPS USING REDUX AND THIS IS THE ACTUAL 'FINAL' DATA USED FOR FURTHER CALCS AND RENDERING
            const { details } = this.props;

             // HERE I'M SENDING THE 'CLICKED' VALUE FROM THE PREVIOUS COMPONENT TO THE BACKEND API
            axios.post(`http://localhost:1337/api/`, { 'test' : finalSelect })
                .then(res => {
                console.log('Data send')
                // console.log(res.data);
              }).catch(err => console.error(err));



            // Making the req 
            details.map(x => {

                EmployeeApi.getEmployee(x)
                    .then(y => {
                        //Making sure everything is in the right order
                        let test = Object.assign(y.data);
                        let ii = x;

                    setTimeout(
                        this.setState(prevState => ({
                            ...prevState.currentEmployee,
                            fullNames: [...prevState.currentEmployee.fullNames, ii]
                        })), 100);

                let onlyRelevantDate = [];
                test.map(item => {
                    if (finalSelect == parseInt(item.year + moment().month(item.month).format("MM"), 10)) {
                            onlyRelevantDate.push(item)
                        }})
                            this.setState(prevState => ({
                            currentEmployee: {
                            ...prevState.currentEmployee,
                            salaryInfo: [...prevState.currentEmployee.salaryInfo, onlyRelevantDate],
                            fullNames: [...prevState.currentEmployee.fullNames, ii]
                    }}))         
                })
            });
        }   
        componentWillReceiveProps(nextProps) {
            this.getEmployeeSalaryData(nextProps);
        }

        componentWillMount() {
            this.getEmployeeSalaryData(this.props);
        }

【问题讨论】:

  • 如果您不提供实际代码,就无法真正提供帮助。
  • componentWillReceiveProps()?
  • 你是用thunk还是手动写了一个中间件函数?如果用户从组件 A 中选择值 1,然后选择值 2,则会发出 2 个请求,但不能保证这些请求返回的顺序,因此第一个值(值 1)可能在第二次选择之后出现。您可能只是在输入结果时设置结果,而不是按照请求的顺序。你能检查开发者控制台的网络选项卡,看看请求是否正确,响应是否正确,以便我们可以将代码限制为客户端或服务器?
  • 因此,您正在创建一个作为函数的操作并根据异步结果调度操作。您发布的代码并未显示这一点。您可以尝试在 thunk 函数中记录“来自 A 的选择”,看看这是否与 A 正在使用的组件相同。
  • @RayDonovan 出去吃午饭,但我不得不更新我的答案中的示例代码以反映您的问题

标签: javascript node.js reactjs redux sails.js


【解决方案1】:

在组件 A 中,您应该分派一个动作,该动作是一个采用分派函数的函数。

//some click handler for when user makes a selection
//  the function should be in action creator file but you get the jist
const handleSomeClick = someValue =>
  //when you dispatch an action that is a function in redux with thunk then
  //  the thunk middleware will not call next (no reducers will be called)
  //  thunk will pass a parameter to this function that is the dispatch
  //  function so from your function you can dispatch actual object action(s)
  dispatch(
    dispatch=>
      setTimeout(
        dispatch({type:"changedValue",data:someValue}),//dispatching the action
        someValue*1000//assuming someValue is a number
      )
  )

Here 是一个示例,其中组件 A 设置 someValue 取决于单击的按钮,并且将突出显示该按钮,它还将异步设置 B 的 someValue。这是在函数 changeLater 中完成的,该函数调度一个作为函数的操作,因此 thunk 将通过调度执行它。

此函数将在超时后调度一个动作。如果您单击数字 5 和 1(快速),您会看到 A 的突出显示按钮和 B 异步后的值不匹配(A 的突出显示为 1,B 异步后的值显示为 5)。

这是因为用户点击并启动异步进程的顺序与异步进程解析的顺序不同。您可以通过仅在最后一个已解决的承诺时分派操作来解决此问题。

This example 展示了它是如何通过使用由 later 创建的 promise 来完成的,并且只有在它是最后一个时才通过使用名为 lastNumberClickedonlyLastRequestedPromise 的部分应用版本来解决它

【讨论】:

    【解决方案2】:

    你可以使用 RxJS 来解决这个问题

    【讨论】:

      猜你喜欢
      • 2017-05-14
      • 1970-01-01
      • 2016-02-15
      • 2013-03-10
      • 1970-01-01
      • 2017-05-12
      • 1970-01-01
      • 2018-04-09
      • 2017-12-09
      相关资源
      最近更新 更多