【问题标题】:How to get state which comes from props which is got from API in React如何从 React 中的 API 获取来自 props 的状态
【发布时间】:2020-09-25 00:31:42
【问题描述】:

我想做什么

  • 子组件第一次渲染时,我想使用父组件的props中的值

问题

  • 子组件第一次渲染时,子组件中没有设置props状态

我是React 的初学者。我正在尝试使用props 在子组件中的componentDidMount 中通过axios 调用API。我的意思是,我正在做的是在父组件中调用 API,并将此 API 中的数据设置为子组件为props

但是,当我尝试这样做时,props 未在子组件中设置为 state

例如,当我检索包含category 的产品时,我输入localhost:3000/api/parent/?category=1/。但是,我的console.log 向我展示了localhost:3000/api/parent/?category=undefined,因为我猜想在子组件第一次渲染时没有设置 props。 实际上,我可以在state 中看到category 对象,如下所示。

我猜props 完全设置为state 在子组件完成第一次渲染之后。

如何将来自 API 的 props 设置为 state? 虽然我尝试了很多在stackoverflow上找到的解决方案,但我被这个问题卡住了这么长时间。

我想让你告诉我一些解决方案。

非常感谢。

== == ==

我的代码是这样的。

父组件

class Top extends Component {
  constructor(props) {
    super(props);
    this.state = {
      loginUser: '',
      categories: [],
    };
  }
  async componentDidMount() {
    const localhostUrl = 'http://localhost:8000/api/';
    const topCategoryList = ['Smartphone', 'Tablet', 'Laptop'];
    let passCategoryToState=[]
    axios
      .get(localhostUrl + 'user/' + localStorage.getItem('uid'))
      .then((res) => {
        this.setState({ loginUser: res.data });
      })
      .catch((err) => console.log(err));

    await Promise.all(
      topCategoryList.map(async (category) => {
        await axios.get(localhostUrl + 'category/?name=' + category).then((res) => {
          passCategoryToState=[...passCategoryToState, res.data]
          console.log(passCategoryToState);
        });
      })
    );

    this.setState({categories : passCategoryToState})
  }

  render() {
    if (!this.props.isAuthenticated) {
      return <p> Developing now </p>;
    }
    if (this.state.loginUser === '' ) {
      return <CircularProgress />;
    } else {
      return (
        <>
          <Header loginUser={this.state.loginUser} />
          <Give_Item_List
            axiosUrl="http://localhost:8000/api/"
            subtitle="Smartphone Items"
            loginUser={this.state.loginUser}
            category={this.state.categories[0]}
          />
        </>
      );
    }
  }
}

export default Top;

还有,子组件

class Give_Item_List extends Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: false,
      loginUser: this.props.loginUser,
      category: this.props.category,
    };
  }

  async componentDidMount() {
    let pickedGiveItems;
    await this.setState({ loading: true });
    await axios
      .get(this.props.axiosUrl + 'giveitem/?category=' + this.state.category.id)
      .then((res) => {
        pickedGiveItems = res.data;
        console.log(pickedGiveItems);
      })
      .catch((err) => console.log('Not found related to Items'));
    this.setState({ loading: false });
  }

  render() {
    if (this.state.loading == true) {
      return <CircularProgress />;
    }
    return <h1>Give_Item_List</h1>;
  }
}

export default Give_Item_List;

==============

编辑:更改为componentDidUpdate

componentDidUpdate(prevProps) {
  if(prevProps.category != this.props.category){
    let pickedGiveItems;
    this.setState({ loading: true });
    axios
      .get(this.props.axiosUrl + 'giveitem/?category=' + this.props.category.id)
      .then((res) => {
        pickedGiveItems = res.data;
        console.log(pickedGiveItems);
      })
      .catch((err) => console.log('NotFount'));
    this.setState({ loading: false });
  }
}

还是不行……

【问题讨论】:

    标签: reactjs asynchronous react-props setstate


    【解决方案1】:

    在构造函数中,this.props是未定义的,但是可以直接访问props。

    constructor(props) {
      super(props);
      this.state = {
        loading: false,
        loginUser: props.loginUser,
        category: props.category,
      };
    }
    

    但是,我现在应该注意,将 props 存储在 state 中是一种常见的 react 反模式,您应该始终在需要的地方使用来自 this.props 的 prop 值。

    例如:

    async componentDidMount() {
      let pickedGiveItems;
      await this.setState({ loading: true });
      await axios
        .get(this.props.axiosUrl + 'giveitem/?category=' + this.props.category.id)
        .then((res) => {
          pickedGiveItems = res.data;
          console.log(pickedGiveItems);
        })
        .catch((err) => console.log('Not found related to Items'));
      this.setState({ loading: false });
    }
    

    您也不能await 响应状态更新,因为它不是异步函数,也不会返回 Promise。只需提供一个初始的真实加载状态,并在获取请求解决时切换为 false。

    class Give_Item_List extends Component {
      constructor(props) {
        super(props);
        this.state = {
          loading: true
        };
      }
    
      async componentDidMount() {
        let pickedGiveItems;
        
        await axios
          .get(this.props.axiosUrl + 'giveitem/?category=' + this.props.category.id)
          .then((res) => {
            pickedGiveItems = res.data;
            console.log(pickedGiveItems);
          })
          .catch((err) => console.log('Not found related to Items'));
        this.setState({ loading: false });
      }
    
      render() {
        if (this.state.loading) {
          return <CircularProgress />;
        }
        return <h1>Give_Item_List</h1>;
      }
    }
    

    【讨论】:

    • 感谢您的回答。我尝试了我教给我的东西,但它不起作用。 Console.log 仍然说 cateogry.idundefined...
    • @Toshi023Yuki 你在哪里登录category.id?父组件中的categories 最初是一个空数组,因此传递给子组件的this.state.categories[0] 在初始渲染时将是未定义的。如果您需要对 category 属性更改做出反应,那么您还应该实现 componentDidUpdate 并在 category.id 更改时在子组件中进行获取。
    • 老实说,我从未使用过componentDidUpdate。我试着像你教我的那样使用它,但它不起作用。我将关于componentDidUpdate 的新代码添加到我的问题中。如果你没问题,我希望你告诉你哪里出了问题。
    • @Toshi023Yuki 不用担心。您可以尝试创建重现问题的代码的codesandbox 并在此处分享吗?实时调试代码以查看道具可能会或可能不会随时间变化可能会更容易。
    • 感谢您的大力支持。我创建了一个新的沙箱。老实说,我不能说我以正确的方式创建了它,但我会与你分享链接。这是我的codesandbox。您可能需要密码,所以我会告诉您。 username 是访客,password 是密码 000。您可能会遇到麻烦,因为我正在用日语创建这个应用程序。如果给您带来不便,非常抱歉。
    猜你喜欢
    • 2021-08-03
    • 2021-01-09
    • 1970-01-01
    • 2018-11-14
    • 2018-10-10
    • 1970-01-01
    • 1970-01-01
    • 2023-03-08
    • 2021-10-28
    相关资源
    最近更新 更多