第一个计时器在StackOverflow上!我正在尝试为我的一个投资组合项目模拟一个终端接口。我设想的终端方式是,每个终端盒都有一个带有几个键/值对的状态对象。理想情况下,当有人在接线盒输入表单中输入文本时,输入将被禁用,并且将基于状态已保存的userInput文本以动态响应在屏幕上呈现新的接线盒。我被困住的地方:
我提供了以下每个组件的副本:
App.js
import React from "react";
import Terminal from "./components/Terminal";
import "./App.css";
class App extends React.Component {
render() {
return (
<div>
<Terminal />
</div>
);
}
}
export default App;
Terminal.js
import React, { Component } from "react";
import Form from "./Form";
import Falcon from "./Falcon";
import Messages from "./Alerts/Messages";
class Terminal extends Component {
state = {
output: Messages.intro,
userInput: "",
isComplete: false,
isDisabled: "",
};
markComplete = () => {
this.setState({
isComplete: true,
});
};
onSubmit = (event, userInput) => {
event.preventDefault();
this.setState({
userInput: userInput,
isDisabled: "disabled",
});
};
render() {
return (
<div>
<Falcon
output={this.state.output}
markComplete={this.markComplete}
isComplete={this.state.isComplete}
/>
<p />
<Form
input={this.state.userInput}
onSubmit={this.onSubmit}
isComplete={this.state.isComplete}
isDisabled={this.state.isDisabled}
/>
<p />
</div>
);
}
}
export default Terminal;
Falcon.js ( 注意 :您会看到下面有一个“ Typed”组件-这是Matt Boldt的一部分我正在用来模拟打字的Typed.js(其中react-typed是分支包)软件包。
import React, { Component } from 'react'
import Typed from 'react-typed'
class Falcon extends Component {
state = {
output: this.props.output,
};
render() {
return (
<div>
<Typed
strings={[this.state.output]}
typeSpeed={40}
onComplete={(self) => {
self.cursor.remove();
this.props.markComplete();
}}
/>
</div>
);
}
}
export default Falcon;
Form.js
import React from "react";
class Form extends React.Component {
state = {
input: this.props.input,
};
render() {
return (
<form
style={{
display: this.props.isComplete === false ? "none" : "",
}}
onSubmit={(event) => {
this.props.onSubmit(event, this.state.input);
}}
>
{"> "}
<input
ref={(input) => input && input.focus()}
type="text"
disabled={this.props.isDisabled}
style={{
border: "none",
outline: "none",
backgroundColor: "#FFF",
color: "#000",
}}
value={this.state.input}
onChange={(event) => this.setState({ input: event.target.value })}
/>
</form>
);
}
}
export default Form;
非常感谢您提供的见解或指导!感谢您帮助这个“新手”!
答案 0 :(得分:0)
欢迎使用StackOverflow!我做了一个codesandbox demo,做了一些更改。
在开发React应用程序时,将UI(DOM元素)建模为内部状态的函数是一个好习惯。您更新状态,UI会自动更改,它会反应进行更新。
也就是说,您可能希望考虑仅将表单用于终端底部的实际输入元素。 “过去缓冲区”只是一个数组,只能通过用户输入和程序输出来增加其内容。另一个好的做法(实际上是一条诫命!)是永远不要改变状态。因此,如果要更新阵列,则可以从头开始创建一个新阵列,如:
this.setState((state) => ({
conversation: [
...state.conversation, // we spread the previous state into the new one
{ text: state.userInput, id: faker.random.uuid(), type: "input" } // the last element is appended
]
}));}
请注意setState(在类组件中)如何仅计划您所使用的字段的更新。随着应用程序的扩展,您可能需要限制此数组的长度。
终端组件可能像这样:
class Terminal extends Component {
state = {
output: "Messages.intro",
userInput: "",
isComplete: false,
isDisabled: "",
conversation: [] // couldn't think of a nice name :(
};
markComplete = () => {
this.setState({
isComplete: true
});
};
onChange = (event) => {
this.setState({ userInput: event.target.value });
};
onSubmit = (event) => {
event.preventDefault();
this.setState((state) => ({
userInput: "",
conversation: [
...state.conversation,
{ text: state.userInput, id: faker.random.uuid(), type: "input" }
]
}));
};
render() {
const { conversation, userInput, output, isComplete } = this.state;
return (
<div>
<Falcon
output={output}
markComplete={this.markComplete}
isComplete={isComplete}
/>
<p />
// This is not really a form. Should be changed to another readonly element
{conversation.map((item, index) => (
<Form
key={item.id}
input={item.text}
onSubmit={this.onSubmit}
isComplete={isComplete}
isDisabled
/>
))}
<p />
<Form
input={userInput}
onSubmit={this.onSubmit}
isComplete={isComplete}
isDisabled={false}
onChange={this.onChange}
/>
<p />
</div>
);
}
}