简体   繁体   English

反应Redux派遣

[英]React Redux Dispatch

What is the best way to call a dispatch to get initial data on a React component. 调用分派以获取React组件上的初始数据的最佳方法是什么。 My understanding is that ComponentWillMount is called before render. 我的理解是ComponentWillMount在渲染之前被调用。 So in theory if I call dispatch on ComponentWillMount, by the time I hit render and then ComponentDidMount I should have my data in the component's props, right? 因此,从理论上讲,如果我在ComponentWillMount上调用dispatch,那么在我点击渲染然后到ComponentDidMount时,我应该将数据保存在组件的道具中,对吗? I'm not seeing that. 我没看到

I'm seeing that render gets called twice and that on the first go when the component is being initialized, I cannot access the data in props. 我看到渲染两次被调用,并且在组件初始化时第一次调用,我无法访问props中的数据。 It also seems like dispatch does not actually get called until the second render. 似乎直到第二个渲染才真正调用dispatch。 I'm basically looking to have some light shed on the best way to call a dispatch when initially setting up a component. 我基本上是希望在最初设置组件时能找到一些最好的方法来调用调度。 I'm essentially trying to do something like the following where I use a container component to get my data from dispatch and then pass it to a child component as props. 我实质上是在尝试执行以下操作,其中我使用容器组件从调度中获取数据,然后将其作为道具传递给子组件。 But I also want to initialize some state variables in the ContainerComponent and then pass them to the ChildComponent as props. 但我也想在ContainerComponent中初始化一些状态变量,然后将它们作为道具传递给ChildComponent。 The thing is that the state variables I want to initialize depend on the data returned from dispatch and ideally I would do the initialization in ComponentWillMount or ComponentDidMount. 问题是我要初始化的状态变量取决于分派返回的数据,理想情况下,我将在ComponentWillMount或ComponentDidMount中进行初始化。

import React from 'react';
import axios from 'axios';

import { connect } from 'react-redux';
import ChildComponent from './ChildComponent.js';

import { getTransactionsAll } from '../actions/actions.js';

class ContainerComponent extends React.Component {
  constructor() {
    super();
    this.state = {
      acctList:[],
      acctChecked:[],
      categoryList:[]
    }
}
  componentWillMount() {

    console.log("componentWillMount entered");

    this.props.get_data();
    console.log(this.props.searchProps.transactions_all);//this is undefined meaning the dispatch has not assigned the data yet...??

  }

  componentDidMount() {
    console.log("componentDidMount entered");
    console.log(this.props.searchProps.transactions_all);//this is undefined meaning the dispatch has not assigned the data yet...??
}

  render() {

    console.log("TransactionManagerContainer render entered");
    console.log(this.props.searchProps.transactions_all);//this is undefined the first time around meaning the dispatch has not assigned the data yet...??, but is defined on the second call to render after the dispatch has actually occurred...

return <ChildComponent
             data={this.props.searchProps.data}/>;
}

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

export default connect(mapStateToProps, {getTransactionsAll})(TransactionManagerContainer);

Here is my reducer that assigns the state: 这是分配状态的我的减速器:

import { combineReducers } from 'redux'

import {GET_TRANSACTIONS } from '../actions/actions.js'
import {GET_TRANSACTIONS_ALL } from '../actions/actions.js'

const INITIAL_STATE = { defaultYear: 2016, transactions: []};

function get_transactions(state = INITIAL_STATE, action) {
  // console.log("this is in the reducer: get_transactions");
  // console.log(action);
  switch(action.type) {
    case GET_TRANSACTIONS:
      // return { ...state, transactions: action.payload };
      return Object.assign({}, state, {
        transactions: action.payload,
        selectedYear: action.selectedYear
      })
    default:
      return state;
  }
}

function get_transactions_all(state = INITIAL_STATE, action) {
  console.log("this is the value of action in the reducer: get_transactions_all");
  console.log(action);
  switch(action.type) {
    case GET_TRANSACTIONS_ALL:
      // return { ...state, transactions: action.payload };
      return Object.assign({}, state, {
        transactions_all: action.payload
      })
      console.log("this is the value of state in the reducer after being set");
      console.log(state);
    default:
      return state;
  }
}

const rootReducer = combineReducers({
  //stateProps: get_transactions,
  searchProps: get_transactions_all
})

export default rootReducer

Here are my actions: 这是我的动作:

import axios from 'axios';

export const GET_TRANSACTIONS = 'GET_TRANSACTIONS';

export function getTransactions(year) {
 return function(dispatch) {
  axios.get(`http://localhost:3001/api/transfilter?year=${year}&grouping=2`)
   .then(response => {
     dispatch({
       type: GET_TRANSACTIONS,
       payload: response.data,
       selectedYear: year
     });
   })
   .catch((error) => {
     console.log(error);
   })
 }
}

export const GET_TRANSACTIONS_ALL = 'GET_TRANSACTIONS_ALL';

export function getTransactionsAll(year) {
 return function(dispatch) {
  axios.get(`http://localhost:3001/api/trans?limit=20`)
   .then(response => {

     dispatch({
       type: GET_TRANSACTIONS_ALL,
       payload: response.data
     });
   })
   .catch((error) => {
     console.log(error);
   })
 }
}

I believe your main question is: 我相信您的主要问题是:

What is the best way to call a dispatch to get initial data on a React component? 调用分派以获取React组件上的初始数据的最佳方法是什么?

Getting initial data requests (or any AJAX requests in general) should go in the componentDidMount lifecycle event. 获取初始数据请求(或通常的任何AJAX请求)应该在componentDidMount生命周期事件中进行。

There are a few reasons for this, here are two important: 有几个原因,这里有两个重要的原因:

  1. Fiber, the next implementation of React's reconciliation algorithm, will have the ability to start and stop rendering as needed for performance benefits. Fiber是React调节算法的下一个实现,将能够根据需要启动和停止渲染,以提高性能。 One of the trade-offs of this is that componentWillMount, the other lifecycle event where it might make sense to make an AJAX request, will be “non-deterministic”. 其中一项权衡取舍是componentWillMount,这是另一个可能决定发出AJAX请求的生命周期事件,将是“不确定的”。 What this means is that React may start calling componentWillMount at various times whenever it feels like it needs to. 这意味着React可能会在需要时随时开始调用componentWillMount。 This would obviously be a bad formula for AJAX requests. 对于AJAX请求,这显然是一个不好的公式。

  2. You can't guarantee the AJAX request won't resolve before the component mounts. 您不能保证在组件安装之前AJAX请求不会得到解决。 If it did, that would mean that you'd be trying to setState on an unmounted component, which not only won't work, but React will yell at you for. 如果确实如此,那意味着您将尝试在未安装的组件上设置setState,这不仅不起作用,而且React也会为您大喊大叫。 Doing AJAX in componentDidMount will guarantee that there's a component to update. 在componentDidMount中执行AJAX可以确保存在要更新的组件。

Credits: I learned that from here , there is also a discussion here . 积分:我了解到,从这里 ,也有讨论这里

Then, there are a lot of smaller question you've raised and it will be hard for me to answer all, but I'll try to cover most: 然后,您提出了许多较小的问题,我将很难回答所有问题,但是我将尽力介绍大多数问题:

  • After reading the above, you now should understand why your data is undefined in componentWillMount and componentDidMount . 阅读以上内容后,您现在应该了解为什么在componentWillMountcomponentDidMount undefined数据的原因。 That's simply because the data has not arrived yet; 那是因为数据还没有到达。
  • It's normal that your data is undefined during the first render of the component. 在组件的第一次渲染期间undefined您的数据是正常的。 Initial render happens before data arrival; 初始渲染发生在数据到达之前;
  • It's normal that the data is defined during the second render. 在第二次渲染期间定义数据是正常的。 The dispatch triggers asynchronous data fetch. dispatch触发异步数据获取。 Right after data comes, a reducer is hit and component gets re-rendered (that's the second re-render). 在数据到来之后,立即点击一个reducer并重新渲染组件(这是第二次重新渲染)。
  • If the child components in your main component require the data - check in the parent render method if data exists pass internal components conditionally, only if data is present. 如果主组件中的子组件需要数据,请检查父render方法是否存在数据(仅当存在数据时)有条件地通过内部组件。 Like so: 像这样:

     class ContainerComponent extends React.Component { // ... omitted for brevity render() { return ( { this.props.searchProps.data ? <ChildComponent data={this.props.searchProps.data} /> : <p>Loading</p> } ); } } 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM