【问题标题】:How to use splice in React Hooks如何在 React Hooks 中使用拼接
【发布时间】:2021-09-27 13:43:17
【问题描述】:

当我在选择框中选择一个 ID 时,我想在名称数组的选定 ID 中放置一个新名称。我使用了 useState 和 useRef,但“拼接”不起作用。我不知道如何将选定的 ID 传递给拼接函数。这对我来说太难了。请帮帮我。

import React, { useRef, useState } from 'react';
const App = ()=>{
  const [names, setNames] = useState([
    {id: 1, text: 'aaa'},
    {id: 2, text: '222'},
    {id: 3, text: 'bbb'},
  ]);
  const [inputText, setInputText] = useState('');
  const [nextId, setNextId] = useState(4);
  const onChange = e => setInputText(e.target.value);
  const inputEl = useRef(null);
  const optionId = useRef(null);
  const onClick = () => {
      const nextNames = names.concat({
        id: nextId,
        text: inputText,
        });
      setNextId(nextId + 1);
      setNames(nextNames);
      setInputText('');
      console.log(inputEl.current);
      console.log(optionId.current);
  };
  const onSelect = id => {
    const nextNames = names.splice(id, 0, {id:id, text: inputText});
  
    setNames(nextNames);
    setInputText('');
  }
  const onRemove = id => {
    const nextNames = names.filter(name => name.id !== id);
    setNames(nextNames);
  };
  const nameList = names.map(name => (
    <li key={name.id} onDoubleClick={()=> onRemove(name.id)}>{name.text}</li>
  ));
  const idOption = names.map((name, index)=>(
     <option key={name.id}>{index}</option>
     ));
  return(
    <div>
      <input value={inputText} onChange={onChange} ref={inputEl}/>
      <button onClick={onClick}>추가</button>
      <select ref={optionId} onSelect={onSelect}>
        <option>ID</option>
            {idOption}
        <option>last</option>
      </select>
      <ul>{nameList}</ul>
    </div>
  );
};

【问题讨论】:

  • splice 获取索引,但您传递的是 id。您是要向数组中添加新元素,还是要尝试更新现有元素?或两者兼有,视情况而定?
  • 我都想要。添加新元素有效,但更新无效。例如,我的代码中有名称 array=['aaa', '222', 'bbb']。当我想用 id:2 输入一个新名称时,它应该被替换。这就是我想要的。

标签: reactjs react-hooks splice


【解决方案1】:

Array.prototype.splice 就地改变它被调用的数组,这几乎是总是不要 想要使用并且当数组是状态的一部分时在 React 中被认为是反模式。您需要对数组进行浅拷贝,以便为 React 的协调过程正确返回新的数组引用。

splice() 方法通过删除或更改数组的内容 替换现有元素和/或添加新元素就地

由于您想向数组中添加新元素更新现有元素,您首先需要搜索数组以确定您需要执行的操作。如果添加新元素,您可以简单地将先前的数组浅复制到新的数组引用中并附加新元素。如果更新现有元素,则将先前的状态映射到新数组是您想要的。

const onSelect = id => {
  setNames(names => {
    // find if match exists
    const match = names.find(name => name.id === id);

    if (match) {
      // match found, map array
      return names.map(name => name.id === id
        ? {
          ...name,
          text: inputText,
        }
        : name
      );
    }
    
    // no match found, concat new data
    return names.concat({ id, text: inputText });
  });
  setInputText('');
}

【讨论】:

    【解决方案2】:

    Splice 接受索引,因此检查 reference 将不起作用。

    但是您应该改用 slice,因为 splice 会改变您正在处理的数组,并且您不应该直接改变 useState 值。有关详细信息,请参阅切片 reference

    尽管如此,你有更好的选择来做你想做的事,比如mapreduce

    这是一个使用 reduce 的例子:

      const onSelect = id => {
        const nextNames = names.reduce((acc, next) => {
          const name = {...next};
    
          // only change the text prop if we find an id match
          if (name.id === id) {
            name.text = inputText;
          }
    
          // copy the name to the new array
          return [...acc, name];
        }, []);
      
        setNames(nextNames);
        setInputText('');
      }
    

    【讨论】:

      【解决方案3】:

      感谢您的回答。但是,它不能正常工作。下面代码的工作正是我想要的。这些代码是类组件样式,但我需要在 React Hooks 中进行相同的工作。请查看下面的代码,如果可能,请更改为带有反应挂钩的代码。谢谢。

      class App extends React.Component {
        constructor() {
          super();
          this.state = {
            components: []
          };
        }
      
        addNewElement(element, selectedIndex) {
          if (selectedIndex == "last") {
            this.state.components.push(element);
          } else {
            this.state.components.splice(selectedIndex, 0, element);
          }
          this.setState({ components: this.state.components });
        }
        render() {
          let input, option;
          // log out state
          console.log(this.state.components);
          return (
            <div>
              <h3>{this.state.components.join(", ")}</h3>
              <input
                placeholder="enter element"
                ref={node => {
                  input = node;
                }}
                />
              <select
                className={this.state.components.length ? "" : "hidden"}
                ref={node => {
                  option = node;
                }}
                >
                <option value="" disabled selected>Insert at index...</option>
                {this.state.components.map((component, index) =>
                                           <option>{index}</option>
                                          )}
                <option>last</option>
              </select>
              <button
                onClick={() => {
                  this.addNewElement(input.value, option.value);
                }}
                >
                Click
              </button>
            </div>
          );
        }
      }
      
      ReactDOM.render(<App />, document.getElementById("root"));
      

      【讨论】:

      • 这不是答案,您应该更新您的问题以包含所有相关代码。您能否也澄清一下“但是,它不能正常工作”的意思。当提到这里的答案时?这个工作代码是不正确的,它正在改变状态对象,这是 React 中的主要反模式。请重新查看我的答案中提供的解决方案,看看它在不改变状态对象的情况下实现了相同的目标。
      • 感谢您的建议。我会更详细地检查它。
      猜你喜欢
      • 2020-01-03
      • 1970-01-01
      • 2023-02-18
      • 2023-02-24
      • 2019-08-02
      • 2019-10-30
      • 2020-08-10
      • 1970-01-01
      • 2020-12-13
      相关资源
      最近更新 更多