最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • nextjs ssr渲染

    正文概述 掘金(少冰)   2020-12-31   530

    next.js使用

    路由映射

    as的功能,在Link后面加上as可以改变url显示的方式,但是原有的功能不会改变,路径的可选修饰符,该修饰符将显示在浏览器URL栏中。

    router.push也是可以使用as功能,在push第二个参数改变一下

    nextjs实际上面没有改变文件结构,所以直接访问是as修改url后的路径是访问不到的.使用koa可以解决这个问题 const handle = app.getRequestHandler()

    nextjs ssr渲染

    Router的钩子

    路由的事件有6种,分别是

    nextjs ssr渲染

    const events = [
      'routerChangeStart',
      'routerChangeComplete',
      'routerChangeError',
      'beforeHistoryChange',
      'hashCahngeStart',
      'hashChangeComplete'
    ]
    function makeEvent(type){
      return (...args)=>{
        console.log(type,...args);
      }
    }
    events.forEach(event=>{
      Router.events.on(event,makeEvent(event))
    })
    

    hashChange是带#的跳转

    historyChange是不带#的跳转

    getInitialProps

    这个方法是nextjs特有的方法,可以在页面中获取数据,仅有pages文件夹下的js文件才会调用这个方法.在服务端就会调用这个方法,不用等到浏览器(客户端)来渲染.但是客户端也偶尔会执行这段代码,当路由跳转到这个页面就是客服端执行.如果是直接打开这个页面就是服务端执行

    const A= ({router,name})=><Link href="/test/test" as="test"><div><Button>123456</Button><Comp prop="132">123{router.query.id}+{name}</Comp></div></Link>
    A.getInitialProps=()=>{
      return {  //return 的所有东西都会当作A组件的props属性供A组件使用
        name:'joke'
      }
    }
    

    nextjs自定义app _app.js

    import  App,{Container} from 'next/app'
    import 'antd/dist/antd.css'
    class myApp extends App{
    
      static async getInitialProps({Component,ctx}){//每次页面切换都会调用这个方法
        co
        let pageProps;
        if(Component.getInitialProps){
          pageProps = await Component.getInitialProps(ctx)
        }
        return {
          pageProps
        } 
      }
    
      render(){
        const {Component,pageProps} = this.props;
        console.log(Component);
        return(
          <Container>
            <Component {...pageProps}></Component>
          </Container>
        )
      }
    }
    export default myApp
    

    自定义_app.js 也有getInitialProps方法,这个方法会传入其他组件作为参数.组件内部也有getInitialProps,这里自定义组件复原了如果组件如果有getInitialProps的方法的内容就把他返回,供组件使用props,不然组件接受不到props.默认的app组件也是这样去做的

    nextjs自定义document

    nextjs ssr渲染

    import Document,{ Html,Head,Main,NextScript } from 'next/document';
    class MyDocument extends Document{
    
      static async getInitialProps(ctx){ //要么不覆盖,覆盖的话就要把原来的props返回出去
        const props = await Document.getInitialProps(ctx)
        return {...props}
      }
    
      render(){
        return (
          <Html>
            <Head>
              <style>
                {`.test {color:red}`}
              </style>
            </Head>
            <body className="test">
              <Main></Main>
              <NextScript></NextScript>
            </body>
          </Html>
        )
      }
    }
    export default MyDocument
    

    next定义样式

    局部样式

    <style jsx>{`//会自动隔离,在其他组件不生效
        a{
          color:blue
        }
        .link{
          color:yellow
        }
      `}
    </style>
    

    全局样式

    <style jsx global>{`//全局生效,不推荐,因为组件卸载之后样式也会消失,全局样式和局部样式可以共存,多加一个style就可以
        a{
          color:blue
        }
        .link{
          color:yellow
        }
      `}
    </style>
    

    css-in-js

    import Document, { Html, Head, Main, NextScript } from "next/document";
    import { ServerStyleSheet } from "styled-components";
    function withLog(Comp) {
      return props => {
        console.log(props);
        return <Comp {...props} />;
      };
    }
    
    class MyDocument extends Document {
      static async getInitialProps(ctx) {
        //要么不覆盖,覆盖的话就要把原来的props返回出去
        const originalRenderPage = await ctx.renderPage;
        const sheet = new ServerStyleSheet();
        try {
          ctx.renderPage = () => {
            return originalRenderPage({
              enhanceApp: App => props =>
                sheet.collectStyles(<App {...props}></App>)
            });
          };
          const props = await Document.getInitialProps(ctx);
          return { ...props,style:<>{props.styles}{sheet.getStyleElement()}</> };
        } finally {
          sheet.seal();
        }
      }
    
      render() {
        return (
          <Html>
            <Head>
              <style>{`.test {color:red}`}</style>
            </Head>
            <body className="test">
              <Main></Main>
              <NextScript></NextScript>
            </body>
          </Html>
        );
      }
    }
    export default MyDocument;
    
    

    .babelrc中添加如下配置

    nextjs ssr渲染

    react hooks

    function组件通过hooks新增了保存state和更新state的能力,通过API 分别是useState和useEffect

    useReduce,useReduce是更新复杂状态比较方便

    useState,useEffect

    import React, { useState, useEffect, useReducer } from "react";
    
    function MyCountFunction() {
      const [count, setCount] = useState(0);
      const [name, setName] = useState("jojo");
      // useEffect(() => {
      //   //组件渲染完成会触发这个回调
      //   const interval = setInterval(() => {
      //     // setCount(2); //这样是将count直接赋值为2
      //     setCount(c => c + 1); //这样是将count作为形参传入,更新count值为返回的结果
      //   }, 1000);
      //   return () => clearInterval(interval); //返回的函数会在组件卸载时候调用
      // }, []);
      useEffect(()=>{
        console.log('effect invoked')
        return ()=>console.log('effect deteched');
      },[])//如果传入name就会在name每次变化时触发useEffect的两个函数,同理count也是一样
      return (
        <div>
          <span> {count} </span>
          <input type="text" value={name} onChange={e => setName(e.target.value)} />
          <div>{name}</div>
        </div>
      );
    }
    
    function countReducer(state, action) {
      switch (action.type) {
        case "add":
          return state + 1;
    
        case "minus":
          return state - 1;
    
        default:
          return state;
      }
    }
    
    function ReduceCountComponent() {
      const [count, dispatchCount] = useReducer(countReducer, 0);
      useEffect(() => {
        //组件渲染完成会触发这个回调
        const interval = setInterval(() => {
          dispatchCount({ type: "add" });
        }, 1000);
        return () => clearInterval(interval); //返回的函数会在组件卸载时候调用
      }, []);
      return <span> {count} </span>;
    }
    
    export default MyCountFunction;
    
    

    useref

    useRef使得函数组件也能实现只有component组件才能实现的API

    usecontext

    nextjs ssr渲染

    nextjs ssr渲染

    nextjs ssr渲染

    直接使用context就是值

    useCallback

    const handleSearchChange = useCallback((event)=>{
        setSearch(event.target.value)
      },[setSearch]) //由于setSearch不会改变 所以数组内不填也可以
    

    useCallback 的作用在于利用 memoize 减少无效的 re-render,来达到性能优化的作用。还是那句老生常谈的话,“不要过早的性能优化”。从实际开发的经验来看,在做这类性能优化时,一定得观察比较优化的结果,因为某个小角落的 callback 就可能导致优化前功尽弃,甚至是适得其反。

    redux

    import { createStore } from 'redux';
    const initialState = {
      count :0
    }
    const add = 'add'
    function reducer(state = initialState,action){
      console.log(state,action);
      switch (action.type) {
        case add:
        return {count:state.count+1}
        default:
          return state
      }
    }
    const store = createStore(reducer,initialState)
    store.dispatch({type:'add'})
    store.subsribe(()=>{//每次在数据变化时会调用这个函数,可以在react中更新状态重新渲染
      console.log(store.getState());
    })
    console.log(store.getState());
    
    export default store
    

    reducer

    应该返回对象而不是返回一个普通字面量,这样才能更新组件

    nextjs ssr渲染

    conbineReducers时,initialState也要合并

    import { createStore, combineReducers } from "redux";
    const initialState = {
      count: 0
    };
    const add = "add";
    function reducer(state = initialState, action) {
      console.log(state, action);
      switch (action.type) {
        case add:
          return { count: state.count + 1 };
        default:
          return state;
      }
    }
    function userReducer(state = { username: "zhangsan" }, action) {
      switch (action.type) {
        case "changeName":
          return { username: action.name };
        default:
          return state;
      }
    }
    const allReducer = combineReducers(reducer,userReducer)
    const store = createStore(allReducer, {count:initialState,user:{username:'zhangsan'}});
    store.dispatch({ type: "add" });
    store.subsribe(() => {
      //每次在数据变化时会调用这个函数,可以在react中更新状态重新渲染
      console.log(store.getState());
    });
    console.log(store.getState());
    
    export default store;
    
    

    action

    import { createStore, combineReducers,applyMiddleware } from "redux";
    import ReduxThunk from 'redux-thunk'
    
    const store = createStore(allReducer, {count:initialState,user:{username:'zhangsan'}},applyMiddleware(ReduxThunk));//applyMiddleware(ReduxThunk)使得action的dispatch内可以传入异步的请求数据
    store.dispatch(异步数据);
    
    import { createStore, combineReducers,applyMiddleware } from "redux";
    import ReduxThunk from 'redux-thunk'
    const initialState = {
      count: 0
    };
    const add = "add";
    function reducer(state = initialState, action) {
      console.log(state, action);
      switch (action.type) {
        case add:
          return { count: state.count + action.num || 1 };
        default:
          return state;
      }
    }
    function userReducer(state = { username: "zhangsan" }, action) {
      switch (action.type) {
        case "changeName":
          return { username: action.name };
        default:
          return state;
      }
    }
    function addSync(num){
      return (dispatch,getState)=>{ //如果是给store.dispatch调用会传入两个参数就是dispatch,getState
        setTimeout(()=>{
          dispatch({type:'add',num})
        },1000)
      }
    }
    const allReducer = combineReducers({counter:reducer,user:userReducer})//合并要传入一个对象
    const store = createStore(allReducer, {counter:initialState,user:{username:'zhangsan'}},applyMiddleware(ReduxThunk));//applyMiddleware(ReduxThunk)使得action的dispatch内可以传入异步的请求数据,第二个参数是状态的对象,要和第一个对象的键对应
    store.dispatch({ type: "add" });
    store.dispatch({ username: "lisi",type:'changName' });
    store.dispatch(addSync(5))
    store.subscribe(() => {
      //每次在数据变化时会调用这个函数,可以在react中更新状态重新渲染
      console.log(store.getState());
    });
    console.log(store.getState());
    
    export default store;
    
    

    异步请求有可能出现一点警告如下

    nextjs ssr渲染

    react-redux

    redux原本是独立于react的,redux有连接react的一种方案

    1. 要用provider在_app里面

    2. provider的作用是使provider下面包裹的元素能够访问provider里面提供的值也就是store

    3. 怎么使用provider

      1. nextjs ssr渲染

      2. 在index里面引入connect组件nextjs ssr渲染

      3. 在export default的地方connect()(组件名) connect()返回一个方法,再调用这个方法所以是两个括号

        export default connect(
          function mapStateToProps(state){
          return { //把一些state转化为props传给A组件,可以在A的props获取值
            count:state.counter.count,
            username:state.user.username
          }
        },function mapDispatchToProps(dispatch){
          return {
            add:(num)=>dispatch({type:'add',num}),//这里不推荐直接用字符串做type
            rename:(name)=>{dispatch({type:'changeName',name:name})}
          }
        })(withRouter(A)) ;
        
          
       
       
       ## react中引入redux
    
    现在在chrome调试工具就能够看到redux选项卡
    
    ## nextjs中的HOC  (HOC是接受组件作为参数并返回新的组件)
    
    ​```javascript
    export default (Comp)=>{ //接受组件返回组件,可以对特定参数进行处理,
      return function TestHocComo({name,otherprops}){
        const name = name + 123;
        return <Comp {...otherprops} name={name}></Comp>
      }
    }
    

    在redux中把props改变

    export default (Comp)=>{
      function TestHocComo({Component,pageProps,...rest}){ //配合_app来使用的话可以接收Component pageProps
        // const name = name + 123;
        console.log(Component,pageProps);
        pageProps&&(pageProps.test=123)
        return <Comp Component={Component} pageProps={pageProps} {...rest}></Comp>
      }
      TestHocComo.getInitialProps = Comp.getInitialProps
      return TestHocComo
    }
    

    这样的好处是把redux内部的代码减少,减少了代码的耦合性,要用的时候只需要包裹一下组件,不必把组件内部代码写的很乱

    redux集成到next

    nextjs ssr渲染

    renderer

    可以使一个组件拥有另一个组件的样式

    layout.jsx

    const Comp = ({ color, children, style }) => (
      <div style={{ color, ...style }}>{children}</div>
    );
    <Contaniner renderer={<div className="header-inner" />}>
              <div className="header-left">
                <div className="logo">
                  {/* <Icon type="github" /> */}
                  <GithubOutlined style={IconStyle} />
                </div>
                <div>
                  <Input.Search
                    placeholder="搜索仓库"
                    value={search}
                    onChange={handleSearchChange}
                    onSearch={handleSearch}
                  />
                </div>
              </div>
              <div className="header-right">
                <div className="user">
                  <Avatar size={40} icon={<UserOutlined />} />
                </div>
              </div>
    </Contaniner>
    <Content>
            <Contaniner
              //  comp="p" //传入默认标签是p
              renderer={<Comp color="red" />}
            >
              {children}
            </Contaniner>
    </Content>
          
    

    Container.jsx

    import {cloneElement} from 'react'
    import { render } from 'react-dom'
    const style = {
      width:'100%',
      maxWidth:800,
      marginLeft:'auto',
      marginRight:'auto',
      paddingLeft:20,
      paddingRight:20
    }
    export default ({
      children,
      // comp:Comp='div', //接收默认组件,解构赋值把形参改为大写
      renderer
    })=>{
      return cloneElement(renderer,{
        style:Object.assign({},renderer.props.style,style),
        children
      })
      // return <Comp style={style}>{children}</Comp>
    }
    

    nextjs ssr渲染

    nextjs ssr渲染是renderer.props.style


    起源地下载网 » nextjs ssr渲染

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元