简体   繁体   English

从 React 中的函数更新状态

[英]Update state from a function in React

I have a class component for my App.我的应用程序有一个类组件。 When the component is mounted I need to run a function getOrder to check with our database if such order exists.当组件被安装时,我需要运行一个函数getOrder来检查我们的数据库是否存在这样的订单。 If it is found, I need to update the state with the data from the order.如果找到,我需要使用订单中的数据更新状态。

Function getOrder is used in several places, so I would like to move it to a separate file.函数getOrder用在好几个地方,所以我想把它移到一个单独的文件中。

Here is what I have now:这是我现在所拥有的:

class App extends React.Component {
  state = {
    data: {}
  }

  getOrder = async () => {
    axios.post('', {})
    .then(response => {
      console.log(response);
      if (response.data.result === true) {
        let result = JSON.parse(response.data.data);
        this.setState({data: result});
      } else {
        alert("Order is not found");
      }
    })
    .catch(error => console.log(error));
  };

  async componentDidMount() {
    await this.getOrder()
  }

  render() {
    return (</>);
  }
}

I would like to move function getOrder outside the component like this:getOrder这样将函数getOrder移到组件外:

const getOrder = async () => {
  axios.post('', {})
  .then(response => {
    console.log(response);
    if (response.data.result === true) {
      let result = JSON.parse(response.data.data);
      this.setState({data: result});
    } else {
      alert("Order is not found");
    }
  })
  .catch(error => console.log(error));
};

class App extends React.Component {
  state = {
    data: {}
  }

  async componentDidMount() {
    await getOrder()
  }

  render() {
    return (</>);
  }
}

How can I update the state of the App from the function getOrder in this case?在这种情况下,如何从函数getOrder更新应用程序的状态?

The short answer is: don't update state from outside a component.简短的回答是:不要从组件外部更新状态。 That leads to tight coupling that makes it hard to extend, refactor and test your components.这会导致紧密耦合,从而难以扩展、重构和测试您的组件。


To refactor this you need to think about which parts of your code are related to fetching order data, and which are related to rendering the outcome.要对此进行重构,您需要考虑代码的哪些部分与获取订单数据相关,哪些部分与呈现结果相关。 Try not to let transport-related details (HTTP statuses, body parsing, etc.) leak out into your components, for example, or display things to the user from your services.尽量不要让与传输相关的细节(HTTP 状态、正文解析等)泄漏到您的组件中,例如,或从您的服务向用户显示内容。

Also I would generally avoid mixing async / await syntax with .then / .catch - at least within each function you should stick to one or the other.此外,我一般会避免混合async / await语法用.then / .catch -在每个功能中至少你应该坚持一个或另一个。

Here's one way to rearrange it, where getOrder returns a promise that either resolves with the parsed data, or rejects with an error message:这是重新排列它的一种方法,其中getOrder返回一个承诺,该承诺要么使用已解析的数据进行解析,要么以错误消息拒绝:

const getOrder = async () => {
  const response = await axios.post('', {});
  if (response.data.result) {
    return JSON.parse(response.data.data);
  }
  throw new Error("Order is not found");
};

Now the component only deals with displaying that data, or the error:现在该组件只处理显示该数据或错误:

class App extends React.Component {
  state = {
    data: {}
  }

  async componentDidMount() {
    try {
      const data = await getOrder();
      this.setState({ data });
    } catch(err) {
      alert(err);
    }
  }

  render() {
    return (</>);
  }
}

You could just return the promise, from axios.post() And then use the promise to update the state within the component.您可以从 axios.post() 返回承诺,然后使用承诺更新组件内的状态。

const getOrder = () => {
   return axios.post('', {})
};

class App extends React.Component {
   state = {
   data: {}
}

async componentDidMount() {
let orderPromise = await getOrder()

orderPromise.then(response => {
console.log(response);
if (response.data.result === true) {
  let result = JSON.parse(response.data.data);
  this.setState({data: result});
} else {
  alert("Order is not found");
}
})
.catch(error => console.log(error));

}

render() {
 return (</>);
}
}

As all refactors: you pass in everything you need as function arguments.与所有重构一样:您将需要的所有内容作为函数参数传递。

So in this case, you pass a reference to the component as a function argument so you can call everything that used to be this.[...] as component.[...] instead.因此,在这种情况下,您将对该组件的引用作为函数参数传递,这样您就可以将所有过去的this.[...]作为component.[...]调用。 Also, because you've moved this function into global/module scope, don't use a const blah = arrow function : there is no this that needs (or can , even) be preserved.此外,因为您已将此函数移动到全局/模块范围内,所以不要使用const blah = arrow function :没有this需要(或可以,甚至)被保留。 Instead, use a normal function getOrder(component, ...) { ...} and then call component.setState(...) in that function once you have the relevant data.相反,使用普通function getOrder(component, ...) { ...} ,然后在获得相关数据后在该函数中调用component.setState(...)

Finally, I would also recommend renaming the function: getOrder doesn't tell anyone what this function does, and as it's no longer contextual to a specific component, it probably should be self-explanatory in its name.最后,我还建议重命名该函数: getOrder不会告诉任何人该函数的作用,并且由于它不再与特定组件相关,因此它的名称可能应该是不言自明的。

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

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