簡體   English   中英

創建 React 組件的不同實例

[英]Creating different instances of a React component

我的問題很簡單:如何創建 React 組件的不同實例?

我正在做一個練習,你必須創建一個投票系統:每個組件都有自己的投票數量。

我遇到的問題是每個組件共享相同數量的選票,而不是分開。

這是代碼:

import React, { useState } from 'react';
import ReactDOM from 'react-dom';

const Anecdote = ({text}) =>
{
    const [votes, setVotes] = useState(0);

    return (
        <React.Fragment>
            <p>{text}</p>
            <p>Votes: {votes}</p>
            <button onClick={() => setVotes(votes + 1)}>vote</button>
        </React.Fragment>
    )
}

const App = (props) => 
{
  const [selected, setSelected] = useState(0);

  function randomizeAnecdote(){
    setSelected(Math.floor(Math.random() * anecdotes.length));
  }

  return (
    <div>
      {props.anecdotes[selected]}
      <br/>
      <button onClick={() => randomizeAnecdote()}>press</button>
    </div>
  )
}

const anecdotes = [
  React.createElement(Anecdote, {text:'If it hurts, do it more often'}),
  React.createElement(Anecdote, {text:'Adding manpower to a late software project makes it later!'}),
  React.createElement(Anecdote, {text:'The first 90 percent of the code accounts for the first 90 percent of the development time...The remaining 10 percent of the code accounts for the other 90 percent of the development time.'}),
  React.createElement(Anecdote, {text:'Any fool can write code that a computer can understand. Good programmers write code that humans can understand.'}),
  React.createElement(Anecdote, {text:'Premature optimization is the root of all evil.'}),
  React.createElement(Anecdote, {text:'Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.'}),
]

ReactDOM.render(
  <App anecdotes={anecdotes} />,
  document.getElementById('root')
)

基本上,function randomizeAnecdote()選擇一個隨機軼事與自己的文本一起顯示。 但是,即使顯示另一個軼事,選票也不會改變。

例如,如果一個軼事有 10 票,而我按下按鈕進行隨機化,則 10 票將保留在那里。

我怎樣才能使每個元素的votes都是唯一的?

要重置投票,您可以收聽useEffect中的text ,並在其更改時將投票設置為 0。

useEffect(() => {
  setVotes(0)
}, [ text ])

此外,在測試時,我發現隨機值與先前值相同的問題。 因此,您可以使用以下技巧:

function randomizeAnecdote(){
  let randomValue = Math.floor(Math.random() * anecdotes.length);
  randomValue = (randomValue === selected ? randomValue + 1 : randomValue) % anecdotes.length;
  setSelected(randomValue);
}

以下是示例代碼:

請注意,它解決了以下問題:

  • 重置新文本的vote計數。
  • 固定隨機化 function 所以沒有重復值
  • 更新了將字符串保存在數組而不是 React.Element 中的代碼

 const { useState, useEffect } = React; const Anecdote = ({text}) => { const [votes, setVotes] = useState(0); useEffect(() => { setVotes(0) }, [ text ]) return ( <React.Fragment> <p>{text}</p> <p>Votes: {votes}</p> <button onClick={() => setVotes(votes + 1)}>vote</button> </React.Fragment> ) } const App = ({anecdotes}) => { const [selected, setSelected] = useState(0); function randomizeAnecdote(){ let randomValue = Math.floor(Math.random() * anecdotes.length); randomValue = (randomValue === selected? randomValue + 1: randomValue) % anecdotes.length; setSelected(randomValue); } return ( <div> <Anecdote text={ anecdotes[selected] } /> <br/> <button onClick={() => randomizeAnecdote()}>press</button> </div> ) } const anecdotes = [ 'If it hurts, do it more often', 'Adding manpower to a late software project makes it later,'. 'The first 90 percent of the code accounts for the first 90 percent of the development time...The remaining 10 percent of the code accounts for the other 90 percent of the development time,'. 'Any fool can write code that a computer can understand. Good programmers write code that humans can understand,'. 'Premature optimization is the root of all evil,'. 'Debugging is twice as hard as writing the code in the first place, Therefore, if you write the code as cleverly as possible, you are, by definition. not smart enough to debug it,'. ] ReactDOM,render( <App anecdotes={anecdotes} />. document.getElementById('root') )
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script> <div id='root' />


更新代碼以維護計數:

其重置為 0 的原因是因為useEffect在文本更改時將投票設置為0 如果需要維護計數,則必須維護復雜的 state。

在以下示例中,state 的類型為:

[ key: string ]: number

其中key是文本,value 是計數。

在理想環境中,我將創建一個 redux 存儲,以更詳細的方式維護這兩個值。 但是對於示例,您可以創建一個map<text, vote>並使用它來顯示/維護計數。

 const { useState, useEffect } = React; const Anecdote = ({text}) => { const [ myState, setMyState ] = useState({}) useEffect(() => { if (.myState[ text ] ) { const state = {..;myState } state[ text ] = 0; setMyState(state), } }. [ text ]) const incrVote = () => { const state = {..;myState } state[ text ] = (state[ text ] || 0) + 1; setMyState(state). } return ( <React:Fragment> <p>{text}</p> <p>Votes. {myState[ text ] || 0}</p> <button onClick={incrVote}>vote</button> </React,Fragment> ) } const App = ({anecdotes}) => { const [selected; setSelected] = useState(0). function randomizeAnecdote(){ let randomValue = Math.floor(Math.random() * anecdotes;length)? randomValue = (randomValue === selected: randomValue + 1. randomValue) % anecdotes;length; setSelected(randomValue), } return ( <div> <Anecdote text={ anecdotes[selected] } /> <br/> <button onClick={() => randomizeAnecdote()}>press</button> </div> ) } const anecdotes = [ 'If it hurts, do it more often', 'Adding manpower to a late software project makes it later.'. 'The first 90 percent of the code accounts for the first 90 percent of the development time..,The remaining 10 percent of the code accounts for the other 90 percent of the development time.'. 'Any fool can write code that a computer can understand, Good programmers write code that humans can understand.', 'Premature optimization is the root of all evil.', 'Debugging is twice as hard as writing the code in the first place, Therefore, if you write the code as cleverly as possible, you are. by definition, not smart enough to debug it.', ] ReactDOM.render( <App anecdotes={anecdotes} />, document.getElementById('root') )
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script> <div id='root' />

處理計數似乎是一種冒險的方式:我永遠不會依賴“臨時”組件的 state 來處理重要的事情,因為它使持久性和跟蹤變得困難。 我不熟悉useState ,但顯然 Javascript 閉包有問題。

我將數據和組件分開(你現在在一起),跟蹤可能的更高組件中的計數(應用程序,在你的情況下,如果你切換到 redux 它會簡化事情)並動態創建軼事。 恕我直言,這將是一個更易於管理的選項。

如果我要編寫代碼,我會以不同的方式處理它。 這是主觀的,所以不要認為它是正確的或錯誤的(我根本不稱自己為專家),但我會為我的想法發表一些評論。

import React from 'react';
import ReactDOM from 'react-dom';

// Anecdote is simple, there is no state, only rendering
// <> is a shortcut for <React.Fragment>, can't use in StackOverflow 
const Anecdote = ({text, votes, incVotes}) =>
  <React.Fragment>
      <p>{text}</p>
      <p>Votes: {votes}</p>
      <button onClick={() => incVotes()}>vote</button>
  </React.Fragment>

// Data and components are separate, I don't merge them
const anecdotes = [
  'If it hurts, do it more often',
  'Adding manpower to a late software project makes it later!',
  'The first 90 percent of the code accounts for the first 90 percent of the development time...The remaining 10 percent of the code accounts for the other 90 percent of the development time.',
  'Any fool can write code that a computer can understand. Good programmers write code that humans can understand.',
  'Premature optimization is the root of all evil.',
  'Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.',
]

// I'd go for a standard declaration of class, at least for the App
class App extends React.Component {

  // I'm not familiar with useState (my bad), so here a classic init for the state 
  // (very verbose, I know)
  constructor(props) {
    super(props);
    // Bogus: it starts with 0, can be fixed obvs
    this.state = { selected: 0, votesCount: props.anecdotes.map(() => 0) };
  }

  // Your function, now external, I find it more readable. It could be improved.
  randomizeAnecdote() {
    const selected = Math.floor(Math.random() * anecdotes.length);
    setState({ selected });
  }

  // I'd use the callback for the state, in case multiple click occurs and
  // React groups the calls.
  // Note that I copy the array, this will simplify the transition to redux.
  // Using "immutable" behaviour is a good habit and simplifies debug.
  incVotes() {
    this.setState(prevState => {
      const votesCount = [...prevState.votesCount];
      votesCount[prevState.selected]++;
      return({ ...prevState, votesCount });
    });
  }

  // Much simpler render, there is no more array of Anecdote
  render() {
    return (
      <div>
        <Anecdote
          text={this.props.anecdotes[selected]}
          votes={this.state.votesCount[selected]}
          incVotes={() => this.incVotes()}
        />
        <br/>
        <button onClick={() => this.randomizeAnecdote()}>press</button>
      </div>
    );
  }

}

ReactDOM.render(
  <App anecdotes={anecdotes} />,
  document.getElementById('root')
)

它可能不會回復您的答案(因為我不知道究竟是哪個閉包被破壞了),但是使用上述方法應該更容易調試和維護。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM