如何避免将setState与回调一起使用

时间:2017-11-01 19:07:18

标签: javascript reactjs

我有以下反应组件(它可以工作),但我使用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
&#13;
&#13;
&#13;

3 个答案:

答案 0 :(得分:3)

为什么不这样?

不是将UI元素存储在状态中,而是存储您要使用的数据,例如src并在您的案例中键入。从render中调用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

答案 1 :(得分:2)

我认为/你认为你正在使用babel和ES7。如果是这样,您可以使用async代替。

使用cb

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

使用async-await

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

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

使用承诺

或者如果你对承诺感到满意。

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))
   }
}

答案 2 :(得分:0)

试试这个:

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);
}