Reactjs React Redux SSR如何抑制从componentDidMount调用的初始操作?

Reactjs React Redux SSR如何抑制从componentDidMount调用的初始操作?,reactjs,redux,react-redux,serverside-javascript,Reactjs,Redux,React Redux,Serverside Javascript,我能够在服务器端预加载所有需要的状态,并将这些初始状态传递给客户端应用程序的redux存储 我已启用redux logger以查看我的应用程序中发生了什么,并且正在从存储中重新提取状态。那是。因为我的组件在componentDidMount期间调用了必要的操作。以下是减速器、动作和组件的示例: // action: import axios from 'axios'; export function fetchNewsTop() { return { type: 'FE

我能够在服务器端预加载所有需要的状态,并将这些初始状态传递给客户端应用程序的redux存储

我已启用redux logger以查看我的应用程序中发生了什么,并且正在从存储中重新提取状态。那是。因为我的组件在
componentDidMount
期间调用了必要的操作。以下是减速器、动作和组件的示例:

// action:
import axios from 'axios';

export function fetchNewsTop() {
    return {
        type: 'FETCH_NEWS_TOP',
        payload: axios.get('/news/top')
    };
}

// reducer:
export function newsArchive(state = {
    pending: false,
    response: { data: [] },
    error: null
}, action) {
    switch (action.type) {
    case 'FETCH_NEWS_TOP_PENDING':
        return { ...state, pending: true, response: { data: [] }, error: null };
    case 'FETCH_NEWS_TOP_FULFILLED':
        return { ...state, pending: false, response: action.payload.data, error: null };
    case 'FETCH_NEWS_TOP_REJECTED':
        return { ...state, pending: false, response: { data: [] }, error: action.payload };
    default:
        return state;
    }
}

// component:
export class NewsArchiveFactory extends React.Component {

    componentDidMount() {
        this.props.fetchNewsTop();
    }

    render() {
        if (this.props.news) {
            return (
                <NewsGrid items={this.props.news} />
            );
        }
        return null;
    }
}
//操作:
从“axios”导入axios;
导出函数fetchNewsTop(){
返回{
键入:“获取新闻”,
有效负载:axios.get(“/news/top”)
};
}
//减速器:
导出功能新闻存档(状态={
待定:错误,
响应:{data:[]},
错误:null
},行动){
开关(动作类型){
案例“获取新闻顶部待定”:
返回{…状态,挂起:true,响应:{data:[]},错误:null};
“获取最新消息”案例:
返回{…状态,挂起:false,响应:action.payload.data,错误:null};
案例“获取新闻”被拒绝:
返回{…状态,挂起:false,响应:{data:[]},错误:action.payload};
违约:
返回状态;
}
}
//组成部分:
导出类NewsArchiveFactory扩展React.Component{
componentDidMount(){
this.props.fetchNewsTop();
}
render(){
如果(这个。道具。新闻){
返回(
);
}
返回null;
}
}
我使用的是
redux承诺中间件
,它创建承诺操作(已完成、已拒绝、待定)

在安装组件时调用该操作。我的理解是,即使在服务器端呈现组件以通知JS它存在,也会调用componentDidMount。组件本身不会重新安装。然而,我也读到,在
componentDidMount
中运行我的操作是一个更好的选择,我个人认为,如果我从
componentdiddupdate
调用它,它甚至不会工作(我们将进入一个无限循环)


我想禁止调用这些初始操作,因为状态已经来自服务器端。如何实现这一点?

我希望有更好的方法,但到目前为止,我想到的是在接收数据时,根据服务器还是客户端接收数据,在reducer状态下设置一个
ssr
标志

首先,
ComponentDidMount
不会在服务器上启动,只在客户端启动。因此,您需要另一种机制,在组件中使用
react-router
match函数以及静态数据获取函数。有关具有易于理解的服务器端数据获取机制的良好样板文件,请参阅。但是,您仍然需要在
ComponentDidMount
方法中获取数据,否则,如果组件仅在客户端上呈现,或者在初始服务器呈现之后装载,则会出现问题。这就是在服务器上预加载数据,但在客户机上触发
ComponentDidMount
时再次请求数据时可能出现的“双重获取”问题

下面是一个解决此问题的示例实现(请注意,我使用的是redux格式,其中操作和还原程序位于一个文件中):

redux/modules/app.js:

import{basepath,fetcher,fetchNeeded,checkStatus}来自“../../lib/api”
const isClient=文档类型!='未定义的'
const SET_FLAG_SSR='app/SET_FLAG_SSR'
const REQUEST_DATA='app/REQUEST_DATA'
const RECEIVE_DATA='app/RECEIVE_DATA'
const DATA\u FAIL='app/DATA\u FAIL'
const INVALIDATE_DATA='app/INVALIDATE_DATA'
常量初始状态={
ssr:错,
初始化:false,
isFetching:false,
迪德:是的,
条件失败:错误,
数据:{}
}
导出默认函数缩减器(state=initialState,action={}){
开关(动作类型){
案例集\u标志\u SSR:
返回Object.assign({},state{
ssr:action.flag
})
案例失效_数据:
返回Object.assign({},state{
迪德:对
})
个案申请资料:
返回Object.assign({},state{
是的,
条件失败:错误,
})
案例接收数据:
返回Object.assign({},state{
ssr:!iClient,
初始化:对,
isFetching:false,
条件失败:错误,
迪德:错,
最新更新:action.receivedAt,
数据:action.data,
})
案例数据\u失败:
返回Object.assign({},state{
isFetching:false,
对,,
})
违约:
返回状态
}
}
函数setFlagSSR(标志){
返回{
类型:SET_FLAG_SSR,
国旗:国旗,
}
}
函数requestData(){
返回{
类型:请求\u数据
}
}
函数receiveData(json){
返回{
类型:接收_数据,
数据:json,
receivedAt:Date.now()
}
}
函数接收失败(错误){
返回{
类型:数据\u失败,
呃:呃,,
}
}
函数获取数据(url){
返回(调度,获取状态)=>{
分派(requestData())
返回获取程序(url,{credentials:'include'},getState().cookie)
.then(response=>response.json())
.then((json)=>{return dispatch(receiveData(json))}
.catch(错误=>{
发送(接收失败(错误))
})
}
}
导出函数getData(){
返回(调度,获取状态)=>{
const state=getState()
if(fetchNeeded(state.app,()=>dispatch(setFlagSSR(false))){
返回分派(fetchData(basepath+'/api/app'))
}
}
}
lib/api.js:

从“fetch ponyfill”导入fetchPonyfill
“蓝鸟”的进口承诺
const{fetch,Request,Response,Headers}=fetchPonyfill(Promise)
const isClient=文档类型!='未定义的'
export const basepath=is