React: componentDidMount + setState not re-rendering the component

时间:2022-08-01 20:11:57

I'm fairly new to react and struggle to update a custom component using componentDidMount and setState, which seems to be the recommended way of doing it. Below an example (includes an axios API call to get the data):

我很擅长使用componentDidMount和setState来更新自定义组件,这似乎是推荐的方法。下面的示例(包括用于获取数据的axios API调用):

import React from 'react';
import {MyComponent} from 'my_component';
import axios from 'axios';


export default class Example extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            data: []
        };
    }

    GetData() {
        return axios.get('http://localhost:5000/<route>');
    }

    componentDidMount() {
        this.GetData().then(
                (resp) => {
                    this.setState(
                        {data: resp.data}
                    )
                }
            )
    }

    render() {
        return (
            <MyComponent data={this.state.data} />
        );
  } 
}

Doing console.log(this.state.data) just below render() shows that this.state.data does indeed get updated (from [] to whatever the API returns). However, the problem appears to be that MyComponent isn't rendered afresh by componentDidMount. From the Facebook react docs:

在render()下面执行console.log(this.state.data)会显示this.state.data确实会更新(从[]到API返回的任何内容)。但是,问题似乎是ComponentDidMount没有重新呈现MyComponent。来自Facebook反应文档:

Setting state in this method will trigger a re-rendering.

在此方法中设置状态将触发重新渲染。

This does not seem to be the case here: The constructor of MyComponent only gets called once (where this.props.data = []) and the component does not get rendered again. I'd be great if someone could explain why this is and whether there's a solution or a different way altogether to get the updating done.

这似乎不是这样的:MyComponent的构造函数只被调用一次(其中this.props.data = [])并且组件不会再次渲染。如果有人可以解释为什么会这样,以及是否有解决方案或完全不同的方式来完成更新,我会很高兴。

UPDATE

UPDATE

I've added the code for MyComponent (minus some irrelevant features, as indicated by ...). console.log(data_array) prints an empty array.

我添加了MyComponent的代码(减去一些不相关的功能,如...所示)。 console.log(data_array)打印一个空数组。

import React from 'react';

class DataWrapper {
  constructor(data) {
    this._data = data;
  }

  getSize() {
    return this._data.length;
  }

     ...
}


export class MyComponent extends React.Component {
      constructor(props) {
        super(props);

        this._dataWrapper = new DataWrapper(this.props.data);

        this.state = {
          data_array: this._dataWrapper,
        };

      }

    render() {
        var {data_array} = this.state;
        console.log(data_array);
        return (
                ...
        );
    }
 }

1 个解决方案

#1


4  

You are falling victim to this antipattern.

你是这个反模式的受害者。

In MyComponent constructor, which only gets called the first time it mounts, passed your empty array through new DataWrapper and now you have some local state which will never be updated no matter what your parent does.

在MyComponent构造函数中,它只在第一次调用时被调用,通过新的DataWrapper传递空数组,现在你有一些本地状态,无论你的父母做什么都不会更新。

It's always better to have one source of truth, just one state object anywhere (especially for things like ajax responses), and pass those around via props. In fact this way, you can even write MyComponent as a simple function, instead of a class.

拥有一个真实来源,在任何地方只有一个状态对象(尤其是像ajax响应之类的东西),并通过道具传递它们总是更好。实际上,通过这种方式,您甚至可以将MyComponent编写为一个简单的函数,而不是类。

class Example extends Component {
  state = { data: [] }

  GetData() { .. }

  componentDidMount() {
    this.GetData().then(res =>
      this.setState({data: new DataWrapper(res.data)})
    )
  }

  render() { return <MyComponent data={this.state.data} /> }
}

...

function MyComponent (props) {
  // props.data will update when your parent calls setState
  // you can also call DataWrapper here if you need MyComponent specific wrapper
  return (
    <div>..</div>
  )
}

#1


4  

You are falling victim to this antipattern.

你是这个反模式的受害者。

In MyComponent constructor, which only gets called the first time it mounts, passed your empty array through new DataWrapper and now you have some local state which will never be updated no matter what your parent does.

在MyComponent构造函数中,它只在第一次调用时被调用,通过新的DataWrapper传递空数组,现在你有一些本地状态,无论你的父母做什么都不会更新。

It's always better to have one source of truth, just one state object anywhere (especially for things like ajax responses), and pass those around via props. In fact this way, you can even write MyComponent as a simple function, instead of a class.

拥有一个真实来源,在任何地方只有一个状态对象(尤其是像ajax响应之类的东西),并通过道具传递它们总是更好。实际上,通过这种方式,您甚至可以将MyComponent编写为一个简单的函数,而不是类。

class Example extends Component {
  state = { data: [] }

  GetData() { .. }

  componentDidMount() {
    this.GetData().then(res =>
      this.setState({data: new DataWrapper(res.data)})
    )
  }

  render() { return <MyComponent data={this.state.data} /> }
}

...

function MyComponent (props) {
  // props.data will update when your parent calls setState
  // you can also call DataWrapper here if you need MyComponent specific wrapper
  return (
    <div>..</div>
  )
}