如何从 Reducer 中删除条目/如何 return 一个新状态? (反应/归还)

How to deleting Entries from Reducer / how to return a new state? (React / Redux)

我的 reducer 默认 return 这个(来自教程):

return [
        {
            id: 1,
            first: "Bucky",
            last: "Roberts",
            age: 71,
            description: "Bucky is a React developer and YouTuber",
            thumbnail: "http://i.imgur.com/7yUvePI.jpg"
        },
        {
            id: 2,
            first: "Joby",
            last: "Wasilenko",
            age: 27,
            description: "Joby loves the Packers, cheese, and turtles.",
            thumbnail: "http://i.imgur.com/52xRlm8.png"
        },
        {
            id: 3,
            first: "Madison",
            last: "Williams",
            age: 24,
            description: "Madi likes her dog but it is really annoying.",
            thumbnail: "http://i.imgur.com/4EMtxHB.png"
        }
    ]
}

我现在希望能够从此 'list' 中删除用户条目。所以我继续构建了一个删除用户操作创建者等,所以除了上面的数据之外,现在在它前面有这段代码:

switch (action.type) {
    case 'USER_DELETED':
        console.log("Hello from reducer-users");
        let newState = Object.assign({}, state, );
        // console.log(newState == state);
        // console.log(newState.users == state.users)
        // delete newState.users;
        return newState;
        break;
}

想法是,如果有人单击 'DELETE USER',将调用此函数并创建一个新状态 return,并删除相应的用户。它在函数被调用的意义上也起作用(显示 console.log)。但是,我不确定现在如何从该列表中删除用户?我知道我需要复制当前状态,然后从副本中删除用户,然后 return 副本,使其成为新状态。这个对吗?如果是这样,我不知道该怎么做。如果我尝试执行上面写的内容,那只是 s.b。在 Whosebug 上写道,我得到一个错误:

user-list.js?1cc2:11 Uncaught TypeError: this.props.users.map is not a function(…)renderList @ user-list.js?1cc2:11render @ ?d41d:33(anonymous function) @ ReactCompositeComponent.js?cd59:793measureLifeCyclePerf @ ReactCompositeComponent.js?cd59:74_renderValidatedComponentWithoutOwnerOrContext @ ReactCompositeComponent.js?cd59:792_renderValidatedComponent @ ReactCompositeComponent.js?cd59:819_updateRenderedComponent @ ReactCompositeComponent.js?cd59:743_performComponentUpdate @ ReactCompositeComponent.js?cd59:721updateComponent @ ReactCompositeComponent.js?cd59:642receiveComponent @ ReactCompositeComponent.js?cd59:544receiveComponent @ ReactReconciler.js?6bfa:126_updateRenderedComponent @ ReactCompositeComponent.js?cd59:751_performComponentUpdate @ ReactCompositeComponent.js?cd59:721updateComponent @ ReactCompositeComponent.js?cd59:642performUpdateIfNecessary @ ReactCompositeComponent.js?cd59:558performUpdateIfNecessary @ ReactReconciler.js?6bfa:158runBatchedUpdates @ ReactUpdates.js?ce09:151perform @ Transaction.js?6dff:138perform @ Transaction.js?6dff:138perform @ ReactUpdates.js?ce09:90flushBatchedUpdates @ ReactUpdates.js?ce09:173closeAll @ Transaction.js?6dff:204perform @ Transaction.js?6dff:151batchedUpdates @ ReactDefaultBatchingStrategy.js?ef70:63batchedUpdates @ ReactUpdates.js?ce09:98dispatchEvent @ ReactEventListener.js?2365:150

这是整个减速器文件:

/*
 * The users reducer will always return an array of users no matter what
 * You need to return something, so if there are no users then just return an empty array
 * */
export default function (state = null, action) {

    switch (action.type) {
        case 'USER_DELETED':
            console.log("Hello from reducer-users");

            //let newState = Object.assign([{}], state);
            // return newState;

            return state.filter(user => user.id !== action.userIdToDelete);
            console.log("UNTIL HERE");
            // console.log(newState.users == state.users)
            // delete newState.users;
            // return ([{
            //     id: 5,
            //     first: "Bucky",
            //     last: "Roberts",
            //     age: 71,
            //     description: "Bucky is a React developer and YouTuber",
            //     thumbnail: "http://i.imgur.com/7yUvePI.jpg"
            // }]);
            break;
            console.log("UNTIL HERE2222");
    }
    return [
        {
            id: 1,
            first: "Bucky",
            last: "Roberts",
            age: 71,
            description: "Bucky is a React developer and YouTuber",
            thumbnail: "http://i.imgur.com/7yUvePI.jpg"
        },
        {
            id: 2,
            first: "Joby",
            last: "Wasilenko",
            age: 27,
            description: "Joby loves the Packers, cheese, and turtles.",
            thumbnail: "http://i.imgur.com/52xRlm8.png"
        },
        {
            id: 3,
            first: "Madison",
            last: "Williams",
            age: 24,
            description: "Madi likes her dog but it is really annoying.",
            thumbnail: "http://i.imgur.com/4EMtxHB.png"
        }
    ]
}

你说得对,你的 reducer 应该 return 状态的新副本,而不改变当前状态。这种方法有一些非常好的好处(参见此处:http://redux.js.org/docs/Glossary.html#reducer

假设这个 reducer 管理的状态是一个数组,要从你的列表中删除一个用户,你可以这样做:

switch (action.type) {
    case 'USER_DELETED':
        return state.filter(user => user.id !== action.userIdToDelete);
}

关键点是 Array.filter return 是一个新数组,将回调应用于每个元素,决定将哪个元素 keep/filter,它不会改变原始数组。在此处查看文档 https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/filter

您可能会想使用 Array.splice 而不是 (https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/splice),但在这种情况下这是错误的,因为 splice "changes the content of an array by removing existing elements and/or adding new elements.",所以它确实改变了原来的。

请注意,您需要在操作负载中传递 userIdToDelete

此外,您不需要 break,因为您已经在使用 return

至于您发布的错误的确切原因,问题是目前您的减速器正在 returning 一个对象而不是数组:let newState = Object.assign({}, state, ); 然后,在您的组件中的某个地方你正在从状态中读取并且你试图在你的状态上调用 map,它不再是一个数组(因此没有为 this.props.users

定义的 map 方法

另一个建议:

我真的建议你开始在你的 reducer 中使用普通的 Js,总是小心改变对象的方法。 在你知道自己在做什么之后,有时在 Js 中使用不可变数据结构可能会很笨拙,因此你可以开始考虑使用这些库来减轻更复杂场景的痛苦(但前提是你确实需要),按复杂性排序(显然在我看来):