Javascript 创建React组件的不同实例

Javascript 创建React组件的不同实例,javascript,reactjs,Javascript,Reactjs,我的问题很简单:如何创建React组件的不同实例 我正在做一个练习,你必须创建一个投票系统:每个组件都有自己的投票数量 我面临的问题是,每个组成部分拥有相同的票数,而不是分开 代码如下: import React, { useState } from 'react'; import ReactDOM from 'react-dom'; const Anecdote = ({text}) => { const [votes, setVotes] = useState(0);

我的问题很简单:如何创建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')
)
import React,{useState}来自“React”;
从“react dom”导入react dom;
常量轶事=({text})=>
{
const[voces,setvoces]=useState(0);
返回(
{text}

投票:{投票}

集合投票(投票+1)}>投票 ) } 常量应用=(道具)=> { const[selected,setSelected]=useState(0); 函数randomizeAnecdote(){ setSelected(Math.floor(Math.random()*轶事.长度)); } 返回( {道具.轶事[精选]}
randomizeAnecdote()}>按 ) } 常数轶事=[ React.createElement(轶事,{text:'如果受伤,就多做一次'), createElement(轶事,{text:'React.createElement为一个后期软件项目添加人力会使它变得更晚!'), React.createElement(轶事,{text:'前90%的代码占前90%的开发时间…剩余的10%的代码占其他90%的开发时间'), createElement(轶事,{text:'任何傻瓜都能写出计算机能理解的代码。好的程序员能写出人类能理解的代码。}), createElement(轶事,{text:'过早优化是万恶之源'), React.createElement(轶事,{text:'调试的难度是最初编写代码的两倍。因此,如果您尽可能巧妙地编写代码,根据定义,您不够聪明,无法调试它。}), ] ReactDOM.render( , document.getElementById('root')) )
基本上,函数
randomizeAnecdote()
会选择一个随机的轶事,并以自己的文本显示。然而,即使在展示另一个轶事时,投票结果也不会改变

举个例子,如果一件轶事有10票,我按下按钮进行随机分组,那么10票就留在那里


如何使
投票
对每个元素都是唯一的?

要重置投票,您可以在
useffect
中收听
文本
,并在其更改时将投票设置为0

useEffect(() => {
  setVotes(0)
}, [ text ])
此外,在测试时,我发现了一个问题,即随机值与以前的值相同。因此,您可以使用以下hack:

function randomizeAnecdote(){
  let randomValue = Math.floor(Math.random() * anecdotes.length);
  randomValue = (randomValue === selected ? randomValue + 1 : randomValue) % anecdotes.length;
  setSelected(randomValue);
}
以下是示例代码:

注意,它解决了以下问题:

  • 重置
    投票
    新文本计数
  • 修正了随机函数,因此不会重复任何值
  • 更新了将字符串保存在数组中而不是React.Element中的代码
const{useState,useffect}=React;
常量轶事=({text})=>{
const[voces,setvoces]=useState(0);
useffect(()=>{
设定投票数(0)
},[正文])
返回(
{text}

投票:{投票}

集合投票(投票+1)}>投票 ) } 常量App=({轶事})=>{ const[selected,setSelected]=useState(0); 函数randomizeAnecdote(){ 让randomValue=Math.floor(Math.random()*轶事.length); randomValue=(randomValue==选定?randomValue+1:randomValue)%轶事。长度; 设置选定值(随机值); } 返回(
randomizeAnecdote()}>按 ) } 常数轶事=[ “如果疼痛,就多做一次”, “为一个后期软件项目增加人力会使它变得更晚!”, '前90%的代码占前90%的开发时间…其余10%的代码占其他90%的开发时间。', “任何傻瓜都能写出计算机能理解的代码。好的程序员能写出人类能理解的代码。”, “过早优化是万恶之源。”, “调试的难度是一开始编写代码的两倍。因此,如果您尽可能巧妙地编写代码,根据定义,您没有足够的智慧来调试它。”, ] ReactDOM.render( , document.getElementById('root')) )

处理计数似乎是一种冒险的方法:我永远不会依赖“临时”组件的状态来处理重要的事情,因为它会使持久性和跟踪都变得困难。我不熟悉
useState
,但显然Javascript闭包有问题

我会将数据和组件分开(你们现在在一起),在更高的组件中记录计数(应用程序,在你们的情况下,如果你切换到redux,它会简化事情),并动态创建轶事。这将是一个更容易管理的选择,imho

如果我要写代码,我会以不同的方式处理它。这是主观的,所以不要认为它是正确的或错误的(我根本不称自己为专家),但我会对我的想法发表一些评论

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')
)
从“React”导入React;
从“react dom”导入react dom;
//轶事很简单,没有状态,只有渲染
//是的快捷方式,不能在StackOverflow中使用
常量轶事=({文本,投票,投票})=>
{text}

投票:{投票}

incvoces()}>投票 //数据和组件是分开的,我不合并它们 常数轶事=[ “如果疼痛,就多做一次”, “为一个后期软件项目增加人力会使它变得更晚!”, '前90%的代码占前90%的开发时间…其余10%的代码占其他90%的开发时间。', “任何傻瓜都能写出计算机能理解的代码。好的程序员能写出人类能理解的代码。”, “过早优化是万恶之源。”, 调试的难度是编写c语言的两倍