【问题标题】:Toggle item in an array react切换数组中的项目反应
【发布时间】:2019-01-23 09:47:59
【问题描述】:

我想切换数组中对象的属性。数组如下所示。这是在反应组件中使用的,当用户单击按钮时,我想切换获胜者。

const initialFixtures = [{
    teams: {
      home: 'Liverpool',
      away: 'Manchester Utd'
    },
    winner: 'Liverpool'
  },
  {
    teams: {
      home: 'Chelsea',
      away: 'Fulham'
    },
    winner: 'Fulham'
  }, ,
  {
    teams: {
      home: 'Arsenal',
      away: 'Tottenham'
    },
    winner: 'Arsenal'
  }
];

我的反应代码看起来像这样

function Parent = () => {

  const [fixtures, setUpdateFixtures] = useState(initialFixtures)
  const toggleWinner = (index) => {
     const updatedFixtures = fixtures.map((fixture, i) => {
           if (i === index) {
                return {
                    ...fixture,
                    winner: fixture.winner === home ? away : home,
                };
            } else {
                return fixture;
            }
     }) 
     setUpdateFixtures(updatedFixtures);
  }

  return <Fixtures fixtures={fixtures} toggleWinner={toggleWinner} />;

}


function Fixtures = ({ fixtures, toggleWinner }) => { 
  fixtures.map((fixture, index) => ( 
    <div>
        <p>{fixture.winner} </p>
    <button onClick = {() => toggleWinner(index)}> Change Winner</button> 
    </div>
  ))
}

代码有效,但感觉有点太多了。我相信有更好更简洁的方法来做到这一点。任何人都可以建议吗?出于架构原因,我确实需要从 Fixture 组件的父级传递固定装置。

【问题讨论】:

  • changeWinner 函数在哪里?
  • 在哪里声明了homeaway 变量?
  • 代码有效,但感觉有点过头了。 代码审查请求在这里是题外话。看CR
  • 快速提问。这是怎么回事:function Parent = () =&gt; { 工作??
  • 它是一个在App中渲染的功能组件。如果这是您要的,它正在使用 Hooks?

标签: javascript arrays reactjs ecmascript-6


【解决方案1】:
const updatedFixtures = [...fixtures];
const fixture = updatedFixtures[i];
updatedFixtures[i] = {
  ...fixture,
  winner: fixture.winner === fixture.teams.home ? fixture.teams.away : fixture.teams.home,
};

【讨论】:

  • 这会改变数组,不是吗?
  • 它只会改变 updatedFixtures 数组。由于这不是状态的一部分(还),你可以随意改变它。
  • 如果您关心的是 const 声明,mdn states thatThe const declaration creates a read-only reference to a value. It does not mean the value it holds is immutable, just that the variable identifier cannot be reassigned.
【解决方案2】:

你可以将slice的fixtures数组分成三部分:

  • 从 0 到 indexfixtures.slice(0, index)。这部分被原封不动地移动到新数组中。

  • index 处的单项。这部分/项目因被更改而被丢弃,并被替换为新项目。

  • 数组的其余部分:fixtures.slice(index + 1)

接下来,将它们放入一个新数组中:

const newFixtures = [
    ...fixtures.slice(0, index),    // part 1
    {/* new item at 'index' */},    // part 2
    ...fixtures.slice(index + 1)    // part 3
];

构建新项目:

  • 使用spread operator

    const newFixture = {
        ...oldFixture,
        winner: /* new value */
    };
    
  • 使用Object.assign

    const newFixture = Object.assign({}, oldFixture, {
        winner: /* new value */
    });
    

【讨论】:

    【解决方案3】:

    如果您以这种方式编写代码 - 这将完成这项工作。

    const toggleWinner = index => {
        const { winner, teams: { home, away } } = fixtures[index];
        fixtures[index].winner = winner === home ? away : home;
    
        setUpdateFixtures([...fixtures]);
    };
    

    将一个新的固定装置数组设置为状态完全足以在Fixtures 组件上触发render

    我为你做了一个working example

    【讨论】:

      【解决方案4】:

      您可以使用 immer 之类的库轻松更新嵌套状态。

      const initialFixtures = [{
          teams: {
            home: 'Liverpool',
            away: 'Manchester Utd'
          },
          winner: 'Liverpool'
        },
        {
          teams: {
            home: 'Chelsea',
            away: 'Fulham'
          },
          winner: 'Fulham'
        }, ,
        {
          teams: {
            home: 'Arsenal',
            away: 'Tottenham'
          },
          winner: 'Arsenal'
        }
      ];
      
      const newState = immer.default(initialFixtures, draft => {
        draft[1].winner = "something";
      });
      
      console.log(newState);
      &lt;script src="https://cdn.jsdelivr.net/npm/immer@1.0.1/dist/immer.umd.js"&gt;&lt;/script&gt;

      【讨论】:

        【解决方案5】:

        如果您习惯于使用基于类的方法,您可以尝试以下方法:

        • 创建一个保存团队属性值的类。
        • 在这个类中创建一个布尔属性,比如isHomeWinner。这家酒店将决定获胜者。
        • 然后创建一个 getter 属性 winner,它将查找 this.isHomeWinner 并提供必要的值。
        • 这将使您拥有一个干净的toggle 函数:this.isHomeWinner = !this.isHomeWinner

        您也可以将toggleWinner 写为:

        const toggleWinner = (index) => {
          const newArr = initialFixtures.slice();
          newArr[index].toggle();
          return newArr;
        };
        

        这看起来很干净且具有声明性。请注意,如果需要不变性,则只需要这样做。如果您对变异值感到满意,只需将 fixture.toggle 传递给您的反应组件。您可能需要绑定上下文,但这也应该有效。

        所以它看起来像:

        function Fixtures = ({ fixtures, toggleWinner }) => { 
          fixtures.map((fixture, index) => ( 
            <div>
              <p>{fixture.winner} </p>
              <button onClick = {() => fixture.toggle() }> Change Winner</button> 
        
              // or
              // <button onClick = { fixture.toggle.bind(fixture) }> Change Winner</button> 
            </div>
          ))
        }
        

        以下是类及其用途的示例:

        class Fixtures {
          constructor(home, away, isHomeWinner) {
            this.team = {
              home,
              away
            };
            this.isHomeWinner = isHomeWinner === undefined ? true : isHomeWinner;
          }
        
          get winner() {
            return this.isHomeWinner ? this.team.home : this.team.away;
          }
        
          toggle() {
            this.isHomeWinner = !this.isHomeWinner
          }
        }
        
        let initialFixtures = [
          new Fixtures('Liverpool', 'Manchester Utd'),
          new Fixtures('Chelsea', 'Fulham', false),
          new Fixtures('Arsenal', 'Tottenham'),
        ];
        
        const toggleWinner = (index) => {
          const newArr = initialFixtures.slice();
          newArr[index].toggle();
          return newArr;
        };
        
        initialFixtures.forEach((fixture) => console.log(fixture.winner))
        console.log('----------------')
        initialFixtures = toggleWinner(1);
        initialFixtures.forEach((fixture) => console.log(fixture.winner))
        
        initialFixtures = toggleWinner(2);
        console.log('----------------')
        initialFixtures.forEach((fixture) => console.log(fixture.winner))

        【讨论】:

        • 感谢您抽出宝贵的时间来回答,但这并不适合我想做的事情。
        【解决方案6】:
              const toggleWinner = (index) => {
                let  updatedFixtures = [...fixtures].splice(index, 1, {...fixtures[index],
                 winner: fixtures[index].winner === fixtures[index].teams.home
                 ? fixtures[index].teams.away : fixtures[index].teams.home})
        
                setUpdateFixtures(updatedFixtures);
              }
        

        【讨论】:

          猜你喜欢
          • 2021-09-06
          • 1970-01-01
          • 2018-02-14
          • 2017-10-18
          • 1970-01-01
          • 2022-01-14
          • 1970-01-01
          • 2020-07-10
          • 1970-01-01
          相关资源
          最近更新 更多