【问题标题】:Deleting / moving around specific item on array in React在 React 中删除/移动数组上的特定项目
【发布时间】:2019-10-23 14:57:38
【问题描述】:

我有以下情况,我制作了一个列表,添加(按下按钮后)一个 React 节点。模型最终布局是这样的

当前代码如下:

import * as React from 'react';
import { Icon } from '../icon/icon';
import { Button } from '../..';

export interface PriorizationListProps {
    children: React.ReactNode;
    limit?: number;
}

export const PriorizationList: React.FunctionComponent<PriorizationListProps> = ({ limit, children }) => {
    const [items, setItems] = React.useState<React.ReactNode[]>([]);

    const move = (currentIndex: number, futureIndex: number) => {
        if (futureIndex !== -1 && futureIndex < items.length) {
            const item = items[currentIndex];
            const movingItem = items[futureIndex];
            items[currentIndex] = movingItem;
            items[futureIndex] = item;
            setItems(items);
        }
    };

    const deleteItem = (index: number) => {
        setItems(prevItems => prevItems.filter((_,i) => i !== index));
    };

    const addItem = () => {
        const newItems = items.concat([children]);
        setItems(newItems);
    };

    const disabledByLimit = () => limit === items.length;

    return (
        <>
            {items.map((item, index) => {
                return (
                    <div className="PriorizationList">
                        <span className="PriorizationList-order">{`${index + 1}.`}</span>
                        <span className="PriorizationList-content">{item}</span>
                        <span className="PriorizationList-icon">
                            <Icon type="pushUp" onClick={() => move(index, index - 1)} />
                            <Icon type="pushDown" onClick={() => move(index, index + 1)} />
                            <Icon type="delete" onClick={() => deleteItem(index)} />
                        </span>
                    </div>
                );
            })}
            <Button type="text" className="PriorizationList-button" onClick={addItem} disabled={disabledByLimit()}>
                <span>Add</span>
                <Icon type="add" />
            </Button>
        </>
    );
};

PriorizationList.defaultProps = {
    limit: 10
};

export default PriorizationList;

我遇到的两个问题是,当我从列表中删除一个项目时,它总是会删除最后一个。并且移动箭头不起作用。 我尝试了多项更改,但都没有成功。

【问题讨论】:

    标签: reactjs typescript react-hooks


    【解决方案1】:

    我相信items.concat([children]) 正在创建新组件,因此您还需要将move()delete() 方法作为回调传递(或将项目作为参数传递)。 此外,items.concat([children]) 正在复制旧组件(包括初始值中的道具)并将它们恢复到状态,因此只有最后一个项目获得最终状态(实际上它可能落后,即你的第一个项目render 传递了一个空的 this.state.items 数组,因为它不会包含自己,因为状态是在创建后设置的)。

    也许尝试转换为基于类的组件,这将允许您明确绑定 this 或使用 renderItems 类型方法生成内容而不创建新组件(如下面的我的 sn-p 所示)

    还有:

    • 避免在适当的情况下使用 [...items] 改变状态数组。
    • 动态生成的内容(例如带有循环或地图)需要 生成的每个项目都有一个唯一的密钥道具。这里我用 Math.random()(可能不适合生产)
    • 你应该检查futureIndex &lt; items.length

    我在 JSX 中创建了一个工作简化/重新设计的示例,它可以帮助你到达你需要去的地方

    使用renderItems的更新片段

    const PriorizationList = () => {
        const [items, setItems] = React.useState([]);
        
        const move = (currentIndex, futureIndex) => {
            if (futureIndex !== -1 && futureIndex < items.length ) {
                const tempItemsAray = [...items]
                const item = tempItemsAray[currentIndex];
                const movingItem = tempItemsAray[futureIndex];
                tempItemsAray[currentIndex] = movingItem;
                tempItemsAray[futureIndex] = item;
                setItems(tempItemsAray);
            }
        };
        const deleteItem = (index) => {
            setItems(prevItems => prevItems.filter((_,i) => i !== index));
        };
        const addItem = () => {
            const id = String(Math.floor(Math.random() * 100000))
            const newItems = [...items , { id }];
            setItems(newItems);
        };
    
        const renderItems = () => {
            return items.map((item, index) => {
                return (
                    <div>
                        <div>
                            <span>Item: {item.id}</span>
                            <button type="pushUp" onClick={() => move(index, index - 1)} >up</button>
                            <button type="pushDown" onClick={() => move(index, index + 1)} >down</button>
                            <button type="delete" onClick={() => deleteItem(index)} >delete</button>
                        </div>
                    </div>
                );
            }) 
        }
    
        return (
            <div>
                <button type="text" onClick={addItem} > Add </button>
                
                {renderItems()}
            </div>
        );
    };
    
    ReactDOM.render(
        <PriorizationList />,
        document.getElementById("react")
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    
    <div id="react"></div>

    上一个片段通过回调传递

    const PriorizationList = () => {
        const [items, setItems] = React.useState([]);
        
        const move = (currentIndex, futureIndex) => {
            if (futureIndex !== -1 && futureIndex < items.length ) {
                const tempItemsAray = [...items]
                const item = tempItemsAray[currentIndex];
                const movingItem = tempItemsAray[futureIndex];
                tempItemsAray[currentIndex] = movingItem;
                tempItemsAray[futureIndex] = item;
                setItems(tempItemsAray);
            }
        };
        const deleteItem = (index) => {
            setItems(prevItems => prevItems.filter((_,i) => i !== index));
        };
        const addItem = () => {
            const id = String(Math.floor(Math.random() * 100000))
            const newItems = [...items , { id , jsx : LineItemJSX }];
            setItems(newItems);
        };
        
        const LineItemJSX = ({deleteItem , move , index , item}) => {
            return (
                <div>
                    <span>Item: {item.id}</span>
                    <button type="pushUp" onClick={() => move(index, index - 1)} >up</button>
                    <button type="pushDown" onClick={() => move(index, index + 1)} >down</button>
                    <button type="delete" onClick={() => deleteItem(index)} >delete</button>
                </div>
            )
        }
        return (
            <div>
                <button type="text" onClick={addItem} > Add </button>
    
                {items.map((item, index) => {
                    const Component = item.jsx
                    return (
                        <Component index={index} key={item.id} deleteItem={deleteItem} move={move} item={item}/>
                    );
                })}
            </div>
        );
    };
    
    ReactDOM.render(
        <PriorizationList />,
        document.getElementById("react")
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    
    <div id="react"></div>
    以项目状态作为道具传递的上一个片段

    const PriorizationList = () => {
        const [items, setItems] = React.useState([]);
        
        const move = (items , currentIndex, futureIndex) => {
            if (futureIndex !== -1 && futureIndex < items.length ) {
                const tempItemsAray = [...items]
                const item = tempItemsAray[currentIndex];
                const movingItem = tempItemsAray[futureIndex];
                tempItemsAray[currentIndex] = movingItem;
                tempItemsAray[futureIndex] = item;
                setItems(tempItemsAray);
            }
        };
        const deleteItem = (index) => {
            setItems(prevItems => prevItems.filter((_,i) => i !== index));
        };
        const addItem = () => {
            const id = String(Math.floor(Math.random() * 100000))
            const newItems = [...items , { id , jsx : LineItemJSX }];
            setItems(newItems);
        };
        
        const LineItemJSX = ({items , index , item}) => {
            return (
                <div>
                    <span>Item: {item.id}</span>
                    <button type="pushUp" onClick={() => move(items ,index, index - 1)} >up</button>
                    <button type="pushDown" onClick={() => move(items ,index, index + 1)} >down</button>
                    <button type="delete" onClick={() => deleteItem(index)} >delete</button>
                </div>
            )
        }
        return (
            <div>
                <button type="text" onClick={addItem} > Add </button>
    
                {items.map((item, index) => {
                    const Component = item.jsx
                    return (
                        <Component index={index} key={item.id} item={item} items={items}/>
                    );
                })}
            </div>
        );
    };
    
    ReactDOM.render(
        <PriorizationList />,
        document.getElementById("react")
    );
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
    
    <div id="react"></div>

    【讨论】:

    • 我已经用更好的方法更新了我的答案,并对正在发生的事情进行了更好的解释。
    猜你喜欢
    • 2019-04-01
    • 2014-09-21
    • 1970-01-01
    • 2016-12-19
    • 1970-01-01
    • 2018-05-03
    • 2021-03-13
    • 2021-10-27
    相关资源
    最近更新 更多