How to share redux state client-side and props server-side in Next JS

5.7k Views Asked by At

I'm a newbie with Next JS.

I use Next JS and Redux.

I have a short code below:

const AdminContainer = (props) => {
  
  return (
    <AdminMasterView>
      <DashboardView studentList={props.studentListServer}/>
    </AdminMasterView>
  )
}

export const getStaticProps = (async () => {

  let response = await db.getInstance().query('SELECT * FROM student_register;');

  return {
    props: {
      studentListServer: response
    }, // will be passed to the page component as props
  }
})

const mapStateToProps = state => ({
  studentList: state.studentInfoReducers.studentList
});

const mapDispatchToProps = {
  getStudentRegisterAction
};

export default connect(mapStateToProps, mapDispatchToProps)(AdminContainer);

I also have studentList (array type) props is declare in Redux. I want to use it to pass data because I have many tasks to do with data such as filter, order,...

Is there any way to use studentList like this and my app still is server rendering first time.

If I dispatch studentListServer to studentList, it still work. But my app isn't server rendering.

<DashboardView studentList={props.studentList}/>

Or easier, I'll check to use props.studentList for client-side and props.studentListServer for server-side. But I think it's not good.

Thank you so much!

2

There are 2 best solutions below

2
On BEST ANSWER

You could use the next-redux-wrapper package. It allows to sync a Redux state on server and client. Consider the example:

export const getStaticProps = wrapper.getStaticProps(async ({ store }) => {
  let response = await db.getInstance().query('SELECT * FROM student_register;');

  // dispatch the action that saves the data
  store.dispatch({ type: 'SET_STUDENTS', payload: response });

  return {
    props: {
      studentListServer: response
    }, // will be passed to the page component as props
  }
})

wrapper.getStaticProps wraps your getStaticProps function with the new parameter store that is a Redux store in fact.

Action with type SET_STUDENTS sets the student list on a server side. When Next.js generates the page, it will save this data in static JSON. So when the page opens on client side, next-redux-wrapper recreates a state dispatching HYDRATE action with saved on a build time static JSON that you can use to restore the studentInfoReducers reducer.

E.g. in your reducer you should implement something like:

import { HYDRATE } from 'next-redux-wrapper';

const initialState = { studentList: [] };

// studentInfoReducers reducer
function reducer(state = initialState, action) {
  // this sets your student list
  if (action.type === 'SET_STUDENTS') {
    return {
      ...state,
      studentList: action.payload,
    };
  }
  
  // this rehydrates your store from server on a client
  if (action.type === HYDRATE) {
    return action.payload.studentInfoReducers;
  }

  return state;
}

So afterwards you should have a valid synced state on client and server at the same time:

const mapStateToProps = state => ({
  studentList: state.studentInfoReducers.studentList // works on server and client
});

Let me know if you have any questions, next-redux-wrapper can be tricky from a first look.

0
On

You don't need to use Redux for that.

Using just cookies you can achieve bidirectional communication, see https://maxschmitt.me/posts/next-js-cookies/

Another example:

Client to Server: manually set a cookie in the client side and then read it in the server with req.headers.cookie or some library like 'cookie'

Server to Client: just read the cookie, and return what you need as a regular prop or update the cookie.

import { useState, useEffect } from "react";
import Cookie from "js-cookie";
import { parseCookies } from "../lib/parseCookies";

const Index = ({ initialRememberValue = true }) => {
  const [rememberMe, setRememberMe] = useState(() =>
    JSON.parse(initialRememberValue)
  );

  useEffect(() => {
    //save/create the cookie with the value in the client
    Cookie.set("rememberMe", JSON.stringify(rememberMe));
  }, [rememberMe]);

  return (
    <div>
      remember me
      <input
        type="checkbox"
        value={rememberMe}
        checked={rememberMe}
        onChange={e => setRememberMe(e.target.checked)}
      />
    </div>
  );
};


Index.getInitialProps = ({ req }) => {
  //read the cookie on the server
  const cookies = parseCookies(req); //parseCookies is a simple custom function you can find 

  return {
   //send the value as a regular prop
    initialRememberValue: cookies.rememberMe
  };
};

export default Index;

Reference: https://github.com/benawad/nextjs-persist-state-with-cookie/blob/master/pages/index.js