在React.js中我应该在componentWillMount或componentDidMount中创建我的初始网络请求吗?

时间:2017-01-12 11:35:03

标签: javascript reactjs

在react文档中,它建议使用componentDidMount方法生成初始网络请求:

  安装组件后立即调用

componentDidMount()。需要DOM节点的初始化应该放在这里。如果您需要从远程端点加载数据,这是实例化网络请求的好地方。在此方法中设置状态将触发重新渲染。

如果在渲染组件之前调用了componentWillMount,那么在此处发出请求并设置状态是不是更好?如果我在componentDidMount中执行此操作,则会呈现组件,发出请求,更改状态,然后重新呈现组件。为什么在呈现任何内容之前提出请求更好?

4 个答案:

答案 0 :(得分:83)

您应该在componentDidMount中执行请求。

  

如果在渲染组件之前调用了componentWillMount,那么在这里发出请求并设置状态是不是更好?

否,因为无论如何在组件呈现时请求都不会完成。

  

如果我在componentDidMount中执行此操作,则会呈现组件,发出请求,更改状态,然后重新呈现组件。为什么在呈现任何内容之前提出请求更好?

因为任何网络请求都是异步。除非您缓存数据,否则无论如何都无法避免第二次渲染(在这种情况下,您根本不需要触发请求)。 你不能通过先前解雇来避免第二次渲染。它无济于事。

在React的未来版本中,我们希望在某些情况下componentWillMount会多次触发,因此您应该使用componentDidMount进行网络请求

答案 1 :(得分:5)

您应该使用componentDidMount

  

为什么在呈现任何内容之前提出请求不是更好?

由于:

  • 您的请求几乎肯定不会在组件呈现之前完成(除非呈现大量标记,或者您处于零延迟量子纠缠连接),并且组件最终需要重新创建大多数时候再次出现
  • componentWillMount也在服务器端呈现期间调用(如果适用)

但是,如果您要问,componentWillMount中启动请求是不是更好(没有实际处理它),我肯定会说是(ES6) ,我自己这样做偶尔会从加载时间缩短几毫秒:

componentWillMount() {
    // if window && window.XMLHttpRequest
    if (!this.requestPromise) {
        this.requestPromise = new Promise(resolve => {
            // ... perform request here, then call resolve() when done.
        });
    }
}

componentDidMount() {
    this.requestPromise.then(data => ...);
}

这将在componentWillMount期间开始预加载您的请求,但该请求仅在componentDidMount中处理,无论该请求是在当时已完成还是仍在进行中。

答案 2 :(得分:4)

您应该在componentDidMount中发出请求,因为不应在componentWillMount中进行副作用请求。可以在componentWillMount中设置setState,如果在componentDidMount中设置了state,则会立即触发第二次重新渲染。

你会读到它是一个反模式(UGHHH)并且一些短信禁止它(eslint-react-plugin),但是我不会非常注意它,因为有时它是与DOM交互的唯一方式。您可以在willMount中设置默认状态,也可以在方法属性(state = {})中设置默认状态,如果您正在使用关联的babel阶段

如你所说,组件将只渲染一次,但这很好,因为你可以显示某种加载器或资源正在加载的任何其他形式的信息。

class MyComp extends Component {

    // What I do with stage 0
    state = { mystate: 1 }

    // What you might want to do if you're not 
    // on the experimental stage, no need to do 
    // the whole constructor boilerplate
    componentWillMount() {
        this.setState({ mystate: 1 });
    }

    componentDidMount() {
        dispatch(yourAction());

        // It's fine to setState here if you need to access 
        // the rendered DOM, or alternatively you can use the ref
        // functions
    }

    render() {
        if (!this.props.myCollection) return <Loader />

        return (
           <div> // your data are loaded </div>
        )
    }
}

答案 3 :(得分:1)

避免在render方法之前进行生命周期钩子获取的真正原因是因为React社区正计划使render方法调用异步。

在此处检查gaeron的回复:https://github.com/reactjs/reactjs.org/issues/302

现在,这意味着在渲染之前将诸如fetch(或与此有关的任何异步操作)的异步动作放置在任何生命周期方法中,将干扰渲染过程。

所以与您今天想像的同步执行不同:

1。构造函数 <<在此处想象触发fetch()>> => 2。 getDerivedStateFromProps <<获取完成,通过事件循环将回调添加到回调队列中>> => 3。渲染 => 4。 componentDidMount => 5.按照添加的顺序执行回调,因此获取回调现在运行。

而是这样:

1。构造函数 <<在此处想象触发fetch()>> => 2。  getDerivedStateFromProps <<,与此同时,提取完成并且回调被排队>> <<想象这里触发异步render()。它的回调也被排队>> =>回调按添加的顺序执行 3。因此提取回调首先运行 => 4。渲染回调运行 => 5。 componentDidMount

这种干扰可能会导致状态更改恢复,因为渲染可能会应用一个较早的状态,该状态会覆盖通过抓取所做的更改。

另一个原因是,componentDidMount生命周期确保了DOM上相应组件的存在,并且如果fetch试图在DOM可用或更新之前尝试操纵DOM,则可能导致应用程序显示错误。