Skip to content
This repository has been archived by the owner on Feb 14, 2023. It is now read-only.

Second argumennt of a reducer doesn't match the one passed to useDispatch. #87

Closed
yezyilomo opened this issue Jun 4, 2019 · 2 comments

Comments

@yezyilomo
Copy link

I think the problem is on useDispatch, when it's calling a reducer it pass a different action object. I even tried to copy and pest your count example on README, I got the same result.

Here is how to reproduce it

import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import { setGlobal, useGlobal, useDispatch } from 'reactn';

let globalStates = {
    names: ["zig", "zag", "zap"],
}

setGlobal(globalStates);

const myReducer = (state, action="hello") => {
    switch(action.type) {
        case "PUSH":
            return [...state.names, action.text];
        case "PULL":
            return state.names.filter(val => val != action.text)
        default:
            return state.names;
    }
}


function Component(props) {
    let [names, setNames] = useGlobal("names");

    let dispatch = useDispatch(myReducer);

    let handleClick = (event) => {
        dispatch({type: 'PUSH', text: "zap"});
    }

    return (
        <div >
            {names}
            <button onClick={handleClick}>PUSH</button>
        </div>
    );
}

export { Component}
@quisido
Copy link
Collaborator

quisido commented Jun 4, 2019

Thank you. The documentation is wrong there. It was correct in 1.x, but should have been updated since! As of 2.x, the second parameter is dispatch, an object that contains and dispatches all of your reducers.

In your example, however, myReducer should be returning { names: ... } instead of ..., because it is returning a partial global state. Think of it like this.setState in a class Component, if you are familiar with those.

// 2.0.x
const myReducer = (state, dispatch, action="hello") => { // added dispatch
    switch(action.type) {
        case "PUSH":
            return { names: [...state.names, action.text] }; // added names property
        case "PULL":
            return { names: state.names.filter(val => val != action.text) };  // added names property
        default:
            return null; // no state change
    }
}
// ...
const dispatch = useDispatch(myReducer);

Issue #82 is not implemented yet, but it will remove this redundancy. I've just released 2.1.1, which allows you to do useDispatch(myReducer, 'names'), which behaves similar to React's native useReducer.

// 2.1.x
const myReducer = (names, action="hello") => { // added dispatch
    switch(action.type) {
        case "PUSH":
            return [...names, action.text];
        case "PULL":
            return names.filter(val => val != action.text)
        default:
            return names;
    }
}
// ...
const dispatch = useDispatch(myReducer, 'names');

You may use either of the two above reducer designs. Both should work.

@quisido quisido closed this as completed in 3aae139 Jun 4, 2019
@yezyilomo
Copy link
Author

Thanks for clarification, I like the 2nd approach, it's easy to follow, and it doesn't change the structure of reducers, unlike the 1st approach. I've upgraded to v2.1.2 and tried it, works really well.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants