0

I can't trigger re-render even the state has changed. PageContainer calls loadPage and loadPage updates state without any inssue. But when the state has changed it dose not trigger re-rendering. It only shows inital state(pageName.loginPage). My expected result is pageName.profilePage since token is already stored on browser. I've also checked debugger state is clearly changed to pageName.profilePage

function PageContainer() {
    const { state, loadPage } = useContainer({
        reducer: loginStatusCheckReducer,
    });

    useEffect(() => {
        loadPage();
    }, [state]); // or [state.page]

    return (
        <>
           {state.page}
        </>
    );
}

And here is useContainer

function useContainer({ reducer }) {
    const [state, dispatch] = useReducer(reducer, { page: pageName.loginPage });
    const loadPage = () => {
        dispatch({ type: actionType.loadPage, dispatch });
    };

    return { state, loadPage };
}

This is the reducer function

function loginStatusCheckReducer(state, action) {
    if (action.type === actionType.loadPage) {
        const token = localStorage.getItem("token");
        if (token) {
            state.api = api(token);
            state.page = pageName.profilePage;
            return state;
        }
    }

    return state;
}


initial state: enter image description here

after loadPage enter image description here

Peter
  • 301
  • 4
  • 17

2 Answers2

2

Looking at the code, I will guess that is not triggering a re-render because your useEffect is passing an empty array, so it will not react to any state changes.

Try adding the variable/state that will change once loaded on the useEffect

function PageContainer() {
const { state, loadPage } = useContainer({
    reducer: loginStatusCheckReducer,
});

useEffect(() => {
    loadPage();
}, [state]); // here the effect will listen to state changes

console.log('state.page', state.page);

return (
    <>
       <h1>{state.page}</h1>
    </>
);}
Ion
  • 1,262
  • 12
  • 19
  • Still not working :( I've tried state.page also. It think it's skipping re-render because useEffect think the [state] or [state.page] is the same as before while it has actually changed. I've just updated my question – Peter Jul 15 '21 at 13:02
  • Yes, it must be a variable or state that will change. First render state.loaded = false, Seconde render = state.loaded = true – Ion Jul 15 '21 at 13:04
  • But it has changed. I've checked chrome debugger and found that the state.page has changed from loginPage(value of `pageName.loginPage`) to profilePage – Peter Jul 15 '21 at 13:09
  • Can you add a console log inside the render method, is important that inside the render the change is logged. – Ion Jul 15 '21 at 13:15
  • Would you specify where should I add logger at? Thank you for the reply! I also added debugger screenshot – Peter Jul 15 '21 at 13:19
  • 1
    Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/234905/discussion-between-ion-and-peter). – Ion Jul 15 '21 at 13:23
1

Following code should fix the issue. @lon has pointed out, state should not be directly mutated.

function loginStatusCheckReducer(state, action) {
    if (action.type === actionType.loadPage) {
        const token = localStorage.getItem("token");
        if (token) {
            //state.api = api(token);
            //state.page = pageName.profilePage;
            //return state;

            return {
                ...state,
                api: api(token),
                page: pageName.profilePage,
            };
        }
    }
}

Peter
  • 301
  • 4
  • 17