Node 和 React 不同步
Node and React are not in sync
我能够实现以下目标 -> 当用户单击组件 A 中的特定日期时,数据将发送到节点 (Sails API),在那里完成所有必要的计算,并且之前组件 B 已呈现正确的数据已准备好显示。
问题是当用户 returns 从组件 B 返回到组件 A 并选择不同的日期时,他/她得到完全相同的结果(旧值),因为即使新值被发送到后端 API,Node 没有使用新值进行重新计算。
我只有在手动刷新页面或更改服务器以强制重新计算后才能获得正确的结果。
我想我需要说明一下,我正在使用 Redux 传递数据,所以问题可能出在这部分。
我会考虑某种类型的自动刷新、动画加载等等。
是的,卡住了:/
是否有可能使它们完全同步?
更新 --> 这是代码:
BACKEND
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);
});
}
FRONTEND
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);
}
在组件 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 shows how it's done by using a promise created by later
and only resolve it if it's the last by using a partially applied version of onlyLastRequestedPromise
调用了 lastNumberClicked
你可以使用 RxJS 来解决这个问题
我能够实现以下目标 -> 当用户单击组件 A 中的特定日期时,数据将发送到节点 (Sails API),在那里完成所有必要的计算,并且之前组件 B 已呈现正确的数据已准备好显示。
问题是当用户 returns 从组件 B 返回到组件 A 并选择不同的日期时,他/她得到完全相同的结果(旧值),因为即使新值被发送到后端 API,Node 没有使用新值进行重新计算。
我只有在手动刷新页面或更改服务器以强制重新计算后才能获得正确的结果。
我想我需要说明一下,我正在使用 Redux 传递数据,所以问题可能出在这部分。
我会考虑某种类型的自动刷新、动画加载等等。 是的,卡住了:/
是否有可能使它们完全同步?
更新 --> 这是代码:
BACKEND
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);
});
}
FRONTEND
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);
}
在组件 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 shows how it's done by using a promise created by later
and only resolve it if it's the last by using a partially applied version of onlyLastRequestedPromise
调用了 lastNumberClicked
你可以使用 RxJS 来解决这个问题