如何避免在回调中使用 setState

IT技术 javascript reactjs
2021-05-17 07:35:16

我有以下react组件(它有效),但我使用 cb 作为 setState。

我想知道如何重构从代码中删除 cb 的代码: this.setState({ viewer: null, document: null }, () => this.getViewer(type, item))

export class DocumentComponent extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      document: null,
      viewer: null,
    }
  }

  getViewer(type, item) {
    let node = null
    switch (type) {
      case 'image':
        node = (
          <Imager url={item.src} />
        )
        this.setState({ viewer: node, document: item })
        break
      default:
        this.setState({ viewer: null, document: null })
        return null
    }
  }

  openViewer(type, item) {
    this.setState({ viewer: null, document: null }, () => this.getViewer(type, item))
  }

  handlerOnClick(item: Object) {
    this.openViewer('image', item)
  }

  render() {
    const { tileData, classes } = this.props
    return (
      <div className={classes.root}>
        <Thumbnailss tileData={tileData} handlerOnClick={item => this.handlerOnClick(item)} />
        {this.state.viewer}
      </div>
    )
  }
}

export default DocumentComponent

3个回答

我假设/您假设您正在使用 babel 和 ES7。如果是这样,您可以async改用。

使用 cb

openViewer(type, item) {
   this.setState({ viewer: null, document: null }, () => this.getViewer(type, item)) 
}

使用异步等待

async openViewer(type, item) {
   await this.setState({ viewer: null, document: null });
   this.getViewer(type, item)
}

我们对这种方法进行了测试,它在我们的环境中运行良好。

使用Promise

或者,如果您对Promise感到满意。

export class DocumentComponent extends React.Component {
   // override and extend setState 

   setState(state) {

     return new Promise((resolve) => {
        super.setState(state, resolve);
     });
   }
   //...
   //...

   openViewer(type, item) {
     this.setState({ viewer: null, document: null })
       .then(() => this.getViewer(type, item))
   }
}

为什么不这样呢?

不是在状态中存储 UI 元素,而是存储您想要使用的数据,例如 src 和您的案例中的类型。getViewer从渲染调用方法它将返回正确的 ui 项目。这样你就不用担心 setState 回调了,每当你更新 type 和 src 的值时,react 都会自动更新 ui。

export class DocumentComponent extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      src: '',
      type: '',
    }
  }

  getViewer() {
    switch (this.state.type) {
      case 'image': return <Imager url={this.state.src} />
      default: return null
    }
  }

  handlerOnClick(item: Object) {
    this.setState({
      type: 'image',
      src: item.src
    })
  }

  render() {
    const { tileData, classes } = this.props
    return (
      <div className={classes.root}>
        <Thumbnailss tileData={tileData} handlerOnClick={item => this.handlerOnClick(item)} />
        {this.getViewer()}
      </div>
    )
  }
}

export default DocumentComponent

试试这个:

setViewer(type, item) {
  switch (type) {
    case 'image':
      const node = (
        <Imager url={item.src} />
      );
      this.setState({ viewer: node, document: item });
      break;
    default:
      this.setState({ viewer: null, document: null });
  }
}

openViewer(type, item) {
  this.setViewer(type, item);
}