简体   繁体   English

在事件中创建和显示新元素 (React.JS)

[英]Creating and displaying new elements on event (React.JS)

I've used stack overflow for the last two years since I picked up programming, but I've never actaully asked a question directly.自从我开始编程以来,过去两年我一直在使用堆栈溢出,但我从来没有直接问过问题。 However, recently I've been running into a problem with React which has stumped me for the last week, and it feels like one of those problems a pro will look at and instantly know the answer to.然而,最近我在使用 React 时遇到了一个问题,这让我在上周感到困惑,感觉就像是专业人士会看到并立即知道答案的问题之一。

My code: https://codepen.io/gooeyWolf/pen/xxZGxGq我的代码: https://codepen.io/gooeyWolf/pen/xxZGxGq

 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <body> <div id="root"><div id="shit"></div></div> <script src="https://unpkg.com/react@16.12.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.development.js"></script> <script src="https://unpkg.com/@babel/standalone@7.8.3/babel.js"></script> <script type="text/babel"> class NameForm extends React.Component { constructor(props) { super(props); this.state = {value: '',}; this.handleChange = this.handleChange.bind(this); } NextThing(){ const element = <h1>Hello, world;</h1>. const divy = document.body;getElementById("div2"). divy;appendChild(element). //document.body;appendChild(element). } handleChange(event) { this:setState({value. event.target;value}). } handleEnter(event){ if(event.key === 'Enter'){ this;NextThing(), } } render() { return ( <div> <span>Are you writing for a protagonist, antagonist, love interest? or secondary character. <br /></span> <input name="flip" id="lucky" value={this.state.value} onChange={this.handleChange} onKeyDown={this;handleEnter} /> <div id="div2"></div> </div> ). } } //onChange={this.handleChange} ReactDOM,render( <NameForm />. document;getElementById('root') ); </script> </body>

The app Im building is pretty simple.我正在构建的应用程序非常简单。 Basically, the app asks you a question, you type in your answer, and it displays a new block of text and a new input box to type your next answer, while leaving previous text on the screen.基本上,该应用程序会问您一个问题,您输入答案,然后它会显示一个新的文本块和一个新的输入框来输入您的下一个答案,同时将之前的文本留在屏幕上。 So far, when you type something and press enter, the programs handles the enter, and calls another function to display the next block of text.到目前为止,当您键入内容并按下回车时,程序会处理回车,并调用另一个 function 来显示下一个文本块。 At first, i tried using return/render statements, but this cause the page to refresh, which would be fine, but the new elements I wanted to display doesn't show up.起初,我尝试使用 return/render 语句,但这会导致页面刷新,这很好,但是我想显示的新元素没有显示出来。 The React.JS course I'm taking advises against using creatElement statements for every new element required, so I'm working with appendChild , which for some reason this runs into errors.我正在学习的 React.JS 课程建议不要对所需的每个新元素使用creatElement语句,因此我正在使用appendChild ,由于某种原因,这会出现错误。 I feel like there has to be a more simple solution to this, and a more reusable solution too.我觉得必须有一个更简单的解决方案,以及一个更可重用的解决方案。 Ideally, it would be able to handle a refresh and keep the previously added elements.理想情况下,它将能够处理刷新并保留先前添加的元素。 I wrote this program in python first, with print and input statements, and it was so easy, but I spent the last week trying figure out the right way with React, but all my solutions seem unnecessarily complicated.我首先在 python 中编写了这个程序,使用 print 和 input 语句,这很容易,但我花了上周试图找出 React 的正确方法,但我所有的解决方案似乎都不必要地复杂。 There has to be a better way... Thank you guys so much, this helps more than I can express.必须有更好的方法......非常感谢你们,这比我能表达的更有用。 Stack Overflow the best (:堆栈溢出最好(:

In React, the common DOM manipulation functions ( appendChild , innerHtml etc) are not the "best" way to do this, there is a more usable solution as you said.在 React 中,常见的 DOM 操作函数( appendChildinnerHtml等)不是做到这一点的“最佳”方式,正如你所说,有一个更有用的解决方案。 What you can do, is take advantage of the way JavaSript expressions can be renderered inside the HTML (That is, those that are inside with {{variable}} with curly braces) and combine it with this.state .您可以做的是利用 JavaSript 表达式可以在HTML中呈现的方式(即,带有{{variable}}和花括号的那些)并将其与this.state结合起来。

First in this.state , define an array div2Children which will contain all the text that is typed into the input首先在this.state中,定义一个数组div2Children ,它将包含输入到输入中的所有文本

// This is inside the constructor
this.state = {value: '', div2Children: []};

Then you can map through each element and convert them in HTML.然后您可以通过每个元素map并在 HTML 中转换它们。

render() {
    return (
        <div>
            <span>Are you writing for a protagonist, antagonist, love interest, or secondary character? <br /></span>
            <input name="flip" id="lucky" value={this.state.value} onChange={this.handleChange} onKeyDown={this.handleEnter} />
            <div id="div2">
                {/* when the array changes this page will also change the HTML */}
                {this.state.div2Children.map(child => (
                    <h1>{child}</h1>
                ))}
            </div>
        </div>
    );
}

Then finally in your NextThing method you'll have to change with this.setState the div2Children array to have all the previous elements but also your newly typed (appending the last element but creating a new array)然后最后在NextThing方法中,您必须使用div2Children this.setState以包含所有先前的元素,但也包含新类型(附加最后一个元素但创建一个新数组)

NextThing(){
    this.setState({div2Children : [...this.state.div2Children, this.state.value]});
}

Note that you will also have to bind NextThing and handleChange .请注意,您还必须绑定NextThinghandleChange Here is a working version这是一个工作版本

 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <body> <div id="root"><div id="shit"></div></div> <script src="https://unpkg.com/react@16.12.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.development.js"></script> <script src="https://unpkg.com/@babel/standalone@7.8.3/babel.js"></script> <script type="text/babel"> class NameForm extends React.Component { constructor(props) { super(props); this.state = {value: '', div2Children: []}; // Bind all the functions this.NextThing = this.NextThing.bind(this); this.handleChange = this.handleChange.bind(this); this.handleEnter = this.handleEnter.bind(this); } NextThing(){ this.setState({div2Children: [...this.state.div2Children, this.state.value]}); } handleChange(event) { this.setState({value: event.target.value}); } handleEnter(event){ if(event.key === 'Enter'){ this.NextThing(); } } render() { return ( <div> <span>Are you writing for a protagonist, antagonist, love interest, or secondary character? <br /></span> <input name="flip" id="lucky" value={this.state.value} onChange={this.handleChange} onKeyDown={this.handleEnter} /> <div id="div2"> {this.state.div2Children.map((child, index) => ( <h1 key={index}>{child}</h1> ))} </div> </div> ); } } //onChange={this.handleChange} ReactDOM.render( <NameForm />, document.getElementById('root') ); </script> </body>

Also notice here that I am also setting a key attribute in the snippet above.另请注意,我还在上面的代码段中设置了一个key属性。 You can find more about that here , I just provided a simple solution which should be fine.你可以在这里找到更多相关信息,我只是提供了一个简单的解决方案,应该没问题。

Firstly, you can't access to the DOM elements like that in React.首先,你不能像 React 那样访问 DOM 元素。 Check the refs react API.检查参考反应 API。 Anyway, I think you should reverse your reflection here and avoid those dom-manipulation (if you can).无论如何,我认为你应该在这里扭转你的反思并避免那些 dom 操纵(如果可以的话)。

The data should be enough to display questions and answers.数据应该足以显示问题和答案。

 class NameForm extends React.Component {
   constructor(props) {
     super(props);
     this.state = {
       step: 1,
       values: [''],
       questions: [
         {
           id: 1,
           label: 'Are you writing for a protagonist, antagonist, love interest, or secondary character?',
         },
         {
           id: 2,
           label: 'Are you happy?',
         }
         // other questions
       ]};
   }
   NextThing = (next) => {
     this.setState((prev) => ({step: prev.step+1, values: [...prev.values, '']}));
   }
   handleChange = (index, event) => {
     event.persist()
     this.setState(state => {
       const values = state.values.map((item, j) => {
         if (j === index) {
           return event.target.value;
         } else {
           return item;
         }
       });

       return {
         values,
       };
     });
   }
   handleEnter = (index, event) => {
     if(event.key === 'Enter' && this.state.step < this.state.questions.length){
       this.NextThing(index);
     }
   }

   render() {
     const { questions, step, values } = this.state;

     return (
       <div>
         {questions.slice(0, step).map((question, index) => (
           <div key={question.id}>
             <span>{question.label}<br /></span>
             <input 
               name={"answer"+question.id} 
               id={"answer"+question.id}
               value={values[index]} 
               onChange={e => this.handleChange(index, e)} 
               onKeyDown={e => this.handleEnter(index, e)} />
           </div>
         ))}
       </div>
     );
   }
 }

ReactDOM.render(
  <NameForm />,
  document.getElementById('root')
);

Let me know if I misunderstood something or if it helps:D让我知道我是否误解了某些内容或是否有帮助:D

As others wrote, you shouldn't try to manipulate DOM like regular javascript in React.正如其他人所写,您不应该尝试像 React 中的常规 javascript 那样操作 DOM。

So;所以; we shouldnt manipulate elements like regular js, but what we can do is we can change stuff inside HTML with Refs and States.我们不应该像普通的 js 那样操作元素,但我们可以做的是我们可以用 Refs 和 States 改变 HTML 里面的东西。 You can use ref's to give an element some kind of "id" in React way, and change its properties.您可以使用 ref 以 React 方式为元素赋予某种“id”,并更改其属性。 State is one of the key elements of React and its quite powerful. State 是 React 的关键元素之一,它非常强大。

https://reactjs.org/docs/state-and-lifecycle.html https://reactjs.org/docs/state-and-lifecycle.html

We can toggle on and off divs, inputs and other elements visibility, innerTexts and etc.我们可以打开和关闭 div、输入和其他元素的可见性、innerTexts 等。

https://reactjs.org/docs/hooks-state.html https://reactjs.org/docs/hooks-state.html

I will use a State Hook to change displaying of a div in here:我将使用 State Hook 在这里更改 div 的显示:

const [testState, setTestState] = useState(false)

... ...

return (
<>
    <h1>Example Page</h1>
    {testState ? <input placeholder="Example Input" /> : null}
</>
)

If my testState is true;如果我的 testState 为真; an input box will show up;会出现一个输入框; and if its false nothing will.如果它是假的,什么都不会。 We can use setTestState(true) -or false- now somewhere in our code to change visibility rendered html block.我们现在可以在代码中的某处使用 setTestState(true) - 或 false- 来更改呈现 html 块的可见性。

Now, not sure if i understood your problem and phyton code correctly (i probably didnt), i quickly made a demo with using state's to toggle an elements visibility.现在,不确定我是否正确理解了您的问题和 phyton 代码(我可能没有),我很快做了一个演示,使用状态来切换元素的可见性。

https://codesandbox.io/s/zealous-taussig-0ctif https://codesandbox.io/s/zealous-taussig-0ctif

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM