DEV Community

loading...
Cover image for Help ssr, use concent to add some material to the nextjs application

Help ssr, use concent to add some material to the nextjs application

fantasticsoul profile image 幻魂 ・6 min read

Open source is not easy, thank you for your support, ❤ star concent^_^

Preface

nextjs is a very popular React server-side rendering application framework. It is very lightweight, easy to use, and has an active community. So when we use react to write an application that requires ssr (server side render), it is basically The city’s first choice is nextjs. concent is a new generation of react state management solution. It has a built-in dependency collection system. It also has the characteristics of 0 intrusion, predictability, gradual and high performance, and provides lifecyle, composition api and other flexible APIs are super simple to write, allowing you to easily control ultra-large-scale react applications.

Hello next

Here we will use the create-next-app command to install a basic next sample application

npx create-next-app hello-next
Enter fullscreen mode Exit fullscreen mode

After execution, you can see a directory structure as follows

|____public
|____pages
| |____ _app.js // The default root component of the next application
| |____index.js // Default homepage
| |____api // api routing file
| | |____hello.js
Enter fullscreen mode Exit fullscreen mode

After we execute npm run dev in the project root directory, we will see a default homepage of ssr driven by next

Hello concent

Here we will use the create-react-app command to install a basic concent sample application

npx create-react-app hello-concent --template concent-ts
Enter fullscreen mode Exit fullscreen mode

After execution, you can see a directory structure as follows

|____index.tsx
|____App.tsx
|____types // store type definition
|____features // List of functional components
| |____counter // counter function
| | |____Counter.tsx // counter component
| | |____model // counter model (including state, reducer, computed)
|____models // Other global model definitions
|____configs
Enter fullscreen mode Exit fullscreen mode

Enter the project directory and execute npm i, and then execute npm start to see a default counter page

You can also click here to understand and edit it online.

Of course, integrating concent in an existing project is also super simple, because it does not need to provide a Provider at the top level, just configure the model in advance.

import {run} from'concent';

run({ // Define a counter model
  counter: {
    state: {num: 1, bigNum: 10 },
    reducer: {
      add(payload, moduleState) {
        return {num: moduleState + 1 };
      },
      async asyncAddBig() {
        await new Promise(resolve => setTimeout(resolve, 1000));
        return {bigNum: moduleState + 10 };
      }
    },
    computed: {
      doubleNum: ({ num }) => num * 2, // This function is triggered only when num changes
    }
  }
})
Enter fullscreen mode Exit fullscreen mode

After that, you can plug and play globally. Both class components and function components can use the same way to read data or call methods, click on the key point, *if the ui is a conditional statement to control whether to consume state or derived data If it is, it is recommended to write delayed deconstruction, so that the minimum granularity of the view to the data collected after each round of rendering *

// ###### Function component
function Demo(){
  // If state and moduleComputed are read on demand, it is recommended to write delayed deconstruction
  const {state: {num, numBig }, moduleComputed: {doubleNum }, mr} = useConcent('counter');
  // ... ui logic, binding data, binding method
}

// ###### Class component
const DemoCls = register('counter')(
  class DemoCls extends React.Component{
   render(){
      const {state: {num, numBig }, moduleComputed: {doubleNum }, mr} = this.ctx;
      // ... ui logic, binding data, binding method
    }
  }
)
Enter fullscreen mode Exit fullscreen mode

Introduce concent in next

There is a _app.js file in the next basic example directory, which is the root component of the next application

import'../styles/globals.css'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default MyApp
Enter fullscreen mode Exit fullscreen mode

Because the model must be configured in advance before using concent, we only need to create a runConcent.js file in advance

import {run} from'concent'
import * as models from'./models';

run(models);
Enter fullscreen mode Exit fullscreen mode

Then import it in the _app.js file, so that all sub-components under the root component can correctly obtain the store's data and mobilize the store's method.

import'../styles/globals.css'
+ import'./runConcent'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default MyApp
Enter fullscreen mode Exit fullscreen mode

Then we create a counter.js file in the next pages directory, representing that this is a page component, so that the browser can use the /counter route to access the rendering view of this component.

import React from'react'
import {useConcent} from'concent'
import router from'next/router'

// use next/router to do browser side router jump
function toHomePage(){
  router.push('/');
}

export default function Counter() {
  const {state, mr, moduleComputed} = useConcent('home')

  return (
    <div>
      this is counter page
      <h1>num: {state.num}</h1>
      <h1>doubleNum: {moduleComputed.doubleNum}</h1>
      <button onClick={mr.add}>add</button>
      <button onClick={toHomePage}>to home page</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

That's it, a next application with concent is created. Isn't it particularly simple? ^_^

Support pre-rendering

next provides two levels of pre-rendering interfaces, namely getServerSideProps and getStaticProps. The difference between the two is the execution timing. getServerSideProps is executed every time a page is requested, while getStaticProps is executed during construction. Let's deal with the situation of getServerSideProps first, and see how to combine concent for pre-rendering support.

First of all, we do not consider the existence of concent. To do pre-rendering support in next, we only need to expose a getServerSideProps interface in your page component.

// This function is called every time a page change is requested
export async function getServerSideProps() {
  // Call external API to get the list of blog posts
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // By returning {props: posts} object, the PostPage component will receive the `posts` parameter when rendering
  return {
    props: {posts },
  }
}

function PostPage({ posts }) {// The posts parameter is received here
  // Render posts...
}

export default PostPage
Enter fullscreen mode Exit fullscreen mode

The reason why Blog can receive posts, in addition to exposing the interface of getServerSideProps, let us observe the content of the root component file of _app.js, and we can find the key points!

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}
export default MyApp
Enter fullscreen mode Exit fullscreen mode

The pageProps in the parameter list is the object pointed to by the props in the return result of getServerSideProps, and then next transmits it to the target page component, so we can deconstruct it in the PostPage parameter list. posts.

So our entry point can start from here, we put the return result of getStaticProps into a format constraint, like a structure like {module:string, state: object}, and then record it in the _app.js file Go to the store

// This function is called on every request
export async function getServerSideProps() {
  // Call external API to get the list of blog posts
  await delay();
  const posts = [
    {id: 1, name:'post1 -----' },
    {id: 2, name:'post2 --- welcome to use concent' },
  ];
  // This returned object will be transparently transmitted to the pageProps of the root component, where the module and the state entity object to which the state belongs are returned
  // record the status to the store there
  return {
    props: {
      module:'test',
      state: {posts },
    }
  };
}
Enter fullscreen mode Exit fullscreen mode

The root component file at this time is changed as follows

import'../styles/globals.css';
+ import'./runConcent';
+ import {setState} from'concent';

function MyApp({ Component, pageProps }) {
  // Record the return status of getServerSideProps to the corresponding module of store here
+ if (pageProps.module) {
+ setState(pageProps.module, pageProps.state);
+}
  return <Component {...pageProps} />
}
export default MyApp;
Enter fullscreen mode Exit fullscreen mode

Then we implemented the page component post-page code as follows

const PostList = React.memo(function () {
  const {state} = useConcent('test');
  return (
    <div>
      {state.posts.map(item => <h3 key={item.id}>{item.name}</h3>)}
    </div>
  );
});

const PostLength = React.memo(function () {
  const {state} = useConcent('test');
  return <h1>{state.posts.length}</h1>;
});

export default function PostPage() {
  return (
    <div>
      <h1>this is post page</h1>
      <PostList />
      <PostLength />
      <button onClick={toHomePage}>to home page</button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Then we open the browser to visit the /post-page page, click to view the source code and you will see that this is a server-side pre-rendered page

For the same reason, we can also replace getServerSideProps with getStaticProps, the whole process above will still work normally, you are welcome to see the clone sample code to experience it yourself.

git clone https://github.com/concentjs/ssr-demo-1
Enter fullscreen mode Exit fullscreen mode

Appendix

doc

-next-js doc
-concent doc

CloudBase CMS

Welcome brothers to pick up CloudBase CMS to create a one-stop cloud content management system, which is developed by the cloud and based on Node.js Headless The content management platform provides a wealth of content management functions, is simple to install, easy for secondary development, and is closely integrated with the cloud development ecosystem to help developers improve development efficiency.

concent has provided strong support for its management background, and the new version of the management interface is more beautiful and considerate.

FFCreator

You are also welcome to pick up FFCreator, it is a lightweight and flexible short video processing library based on node.js. You only need to add a few pictures or video clips and a background music, you can quickly generate a cool video clip.

FFCreator is a lightweight and simple solution, it only requires few dependencies and low machine configuration to quickly start working. And it simulates 90% of the animation effects of animate.css. You can easily convert the animation effects on the web page side into videos, which is really awesome.

Discussion (0)

Forem Open with the Forem app