import React, { useEffect, useRef, useState } from 'react';
import $ from 'jquery';
import 'jquery.terminal/css/jquery.terminal.min.css';
import 'jquery.terminal/js/jquery.terminal.min.js';
import { useRouter } from 'next/router';
const TerminalProfile = ({ width, height }) => {
const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
const days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
const [time, setTime] = useState(getFormattedTime());
const terminalRef = useRef(null);
const [started, setStarted] = useState(false);
const router = useRouter();
const [userData, setUserData] = useState({
Name: 'Yiğitcan',
Surname: 'Uçar',
Email: '[email protected]',
Job: 'Computer Engineer',
City: 'Istanbul',
Country: 'Turkey',
Phone: '+90 555 555 55 55',
Hobbies: 'Programming, Music, Reading, Gaming'
});
useEffect(() => {
const terminal = $(terminalRef.current);
terminal.terminal(
async (command, term) => {
if (command === 'my_profile' && !started) {
setStarted(true);
await startLoadingAnimation(term);
startAnimation(term, 0);
} else if (command === 'logout') {
term.echo('Logging out...');
setTimeout(() => {
term.echo('[[;red;]Redirecting to login page...]');
setTimeout(() => {
router.push('/auth/login'); // Next.js'in yönlendirme metodu
}, 1000);
}, 1000);
} else if (command === 'progress') {
showLoadingAnimation(term);
} else if (command === 'data') {
console.log(userData);
}
else if (command === 'help') {
startHelping(term, 0); // Yardım animasyonunu başlatır
} else if (command.startsWith('Update')) {
const newData = parseUpdateCommand(command);
updateUserData(term, newData);
} else {
term.typing('echo', 20, `Command not recognized: ${command}`);
}
},
{
greetings: () => `Current time is: ${time} on this shell\nPlease type 'help' for more information.`,
name: 'my_terminala',
prompt: '(base) leatherfire@Yigit-MacBook-Pro ~ % ',
css: {
'background-color': 'white',
color: 'black'
}
}
);
}, [userData]);
useEffect(() => {
$(terminalRef.current).css({ width: width + 'px', height: (height - 3) + 'px' });
}, [width, height]);
useEffect(() => {
const interval = setInterval(() => {
setTime(getFormattedTime());
}, 1000);
return () => clearInterval(interval);
}, [getFormattedTime]);
async function startLoadingAnimation(term) {
term.typing('echo', 20, 'Data fetching from the System of WebOS...');
await new Promise(resolve => setTimeout(resolve, 800));
showLoadingAnimation(term);
await new Promise(resolve => setTimeout(resolve, 11000)); // Simulate data fetching delay
}
function showLoadingAnimation(term) {
const size = 30;
const prompt = term.get_prompt();
let string = progress(0, size);
term.set_prompt(string);
let i = 0;
let animation = true; // Değişken var olan "const" tanımından "let" olarak değiştirildi.
(function loop() {
string = progress(i++, size);
term.set_prompt(string);
if (i < 100) {
const timer = setTimeout(loop, 100);
} else {
term.echo(progress(i, size) + ' [[b;green;]OK]')
.set_prompt(prompt);
animation = false;
}
})();
}
function startAnimation(term, step) {
const newUser = {...userData}; // Change userData to newUser
const userDataKeys = Object.keys(newUser); // Use newUser here
if (step < userDataKeys.length) {
const key = userDataKeys[step];
const currentStep = newUser[key]; // Use newUser here
term.typing('echo', 50, `${key} ==> ${currentStep}`, () => {
startAnimation(term, step + 1, newUser); // Use newUser here
});
} else {
term.set_prompt('(base) leatherfire@Yigit-MacBook-Pro ~ % ');
setStarted(false);
}
}
function startHelping(term, step) {
const steps = [
{ command: 'my_profile :', response: `==> Displays your profile.` },
{ command: 'UpdateName <name> :', response: '==> Name updated successfully to your name.' },
{ command: 'UpdateSurname <surname> :', response: '==> Surname updated successfully to your surname.' },
{ command: 'UpdateEmail <email> :', response: '==> Email updated successfully to your email.' },
{ command: 'UpdateJob <job> :', response: '==> Job updated successfully to your job.' },
{ command: 'UpdateCity <city> :', response: '==> City updated successfully to your city.' },
{ command: 'UpdateCountry <country> :', response: '==> Country updated successfully to your country.' },
{ command: 'UpdatePhone <phone> :', response: '==> Phone updated successfully to your phone.' },
{ command: 'UpdateHobbies <hobbies> :', response: '==> Hobbies updated successfully to your hobbies.' },
{ command: 'clear :', response: '==> Clears the terminal.' },
{ command: 'help :', response: '==> This is the help command.' },
{ command: 'logout :', response: '==> Logs out of the profile.' },
];
if (step < steps.length) {
const currentStep = steps[step];
term.typing('echo', 50, currentStep.command, () => {
term.typing('echo', 50, currentStep.response, () => {
startHelping(term, step + 1);
});
});
} else {
term.set_prompt('(base) leatherfire@Yigit-MacBook-Pro ~ % ');
}
}
function updateUserData(term, newData) {
setUserData(newData);
console.log("newData",newData,"\nuserData",userData);
term.typing('echo', 50, `User data updated successfully`);
}
function parseUpdateCommand(command) {
const parts = command.split(' ');
const field = parts[0].replace('Update', ''); // Extract field name
const value = parts.slice(1).join(' '); // Extract value
return { ...userData, [field]: value }; // Merge with existing user data
}
function getFormattedTime() {
const now = new Date();
const dayIndex = now.getDay();
const dayOfWeek = days[dayIndex];
const dayOfMonth = now.getDate();
const monthIndex = now.getMonth();
const month = months[monthIndex];
const year = now.getFullYear();
const hour = now.getHours();
const minute = now.getMinutes();
const second = now.getSeconds();
return `${dayOfWeek} ${month} ${dayOfMonth} ${year} ${hour}:${minute}:${second}`;
}
function progress(percent, width) {
const size = Math.round(width * percent / 100);
let taken = '', i;
for (i = size; i--;) {
taken += '=';
}
if (taken.length > 0) {
taken = taken.replace(/=$/, '>');
}
let left = '';
for (i = width - size; i--;) {
left += ' ';
}
return '[' + taken + left + '] ' + percent + '%';
}
return (
<div className='rounded-b-xl'
ref={terminalRef}
style={{
width: width + 'px',
height: height + 'px',
overflow: 'auto',
padding: '1px',
background: 'white',
color: '#000'
}}
/>
);
};
export default TerminalProfile;
我有一个用 React 构建的自定义终端组件,可以模拟命令行界面。该组件使用“UpdateName”等命令显示和更新用户配置文件数据。然而,尽管新数据对象反映了处理更新的函数内的正确更改,但状态似乎并未立即更新,并且在访问其他函数内的数据时仍然显示旧的配置文件值。似乎存在关闭问题,或者由于 useState 的处理方式而导致状态未正确更新。任何有关解决此问题的建议将不胜感激。
这个功能:
function updateUserData(term, newData) {
setUserData(newData);
console.log("newData",newData,"\nuserData",userData);
term.typing('echo', 50, `User data updated successfully`);
}
当我运行这个函数时,newData和userData是不同的,或者简而言之,userData根本没有改变,始终保持初始值。
例如,通过输入 UpdateName turgut,userData 中的名称应更改为 turgut,但它仍然是 Yiğitcan。
当我输入“UpdateName turgut”时,出现了:
newData {姓名:'turgut',姓氏:'Uçar',电子邮件:'[email protected]',工作:'计算机工程师',城市:'伊斯坦布尔',...}
userData {姓名:'Yiğitcan',姓氏:'Uçar',电子邮件:'[email protected]',工作:'计算机工程师',城市:'伊斯坦布尔',…}
但是为了理解这个问题,我添加了这样的代码:
useEffect(() => {
console.log("\nuseEffect",userData);
}, [userData]);
这次当我输入“updateName turgut”时,它在控制台屏幕上写下了以下内容:
useEffect {姓名:'Yiğitcan',姓氏:'Uçar',电子邮件:'[email protected]',工作:'计算机工程师',城市:'伊斯坦布尔',...}
newData {姓名:'turgut',姓氏:'Uçar',电子邮件:'[email protected]',工作:'计算机工程师',城市:'伊斯坦布尔',...}
userData {姓名:'Yiğitcan',姓氏:'Uçar',电子邮件:'[email protected]',工作:'计算机工程师',城市:'伊斯坦布尔',…}
useEffect {姓名:'turgut',姓氏:'Uçar',电子邮件:'[email protected]',工作:'计算机工程师',城市:'伊斯坦布尔',…}
所以看起来它已经改变了,但由于某种原因旧的仍然出现在函数中。 当我使用这个函数检索数据运行时,它会打印旧数据:
function startAnimation(term, step) {
const newUser = {...userData}; // Change userData to newUser
const userDataKeys = Object.keys(newUser); // Use newUser here
if (step < userDataKeys.length) {
const key = userDataKeys[step];
const currentStep = newUser[key]; // Use newUser here
term.typing('echo', 50, `${key} ==> ${currentStep}`, () => {
startAnimation(term, step + 1, newUser); // Use newUser here
});
} else {
term.set_prompt('(base) leatherfire@Yigit-MacBook-Pro ~ % ');
setStarted(false);
}
}
评论中提供的链接@David 应该可以回答您的问题。我会尝试添加可能的解决方案:
startAnimation
提供新数据作为参数:function startAnimation(term, step, newUser)
startAnimation
的 useEffect
中调用 userData
,这可能看起来有点像这样: React.useEffect(() => {
function startAnimation(term, step) {
const userDataKeys = Object.keys(userData); // Use newUser here
if (step < userDataKeys.length) {
const key = userDataKeys[step];
const currentStep = userData[key]; // Use newUser here
term.typing('echo', 50, `${key} ==> ${currentStep}`, () => {
startAnimation(term, step + 1, userData); // Use newUser here
});
} else {
term.set_prompt('(base) leatherfire@Yigit-MacBook-Pro ~ % ');
setStarted(false);
}
}
startAnimation(terminalRef.current, 0)
}, [userData]);