как вывести возвращенные данные об изменении реквизита в реакции - PullRequest
0 голосов
/ 22 мая 2018

У меня проблемы с выяснением, как получить вызов API для повторного рендеринга на экран.У меня есть функция apiCall, которая передает this.state и изменяет состояние с помощью переданного ref, но она не запускает повторное рендеринг при изменении реквизита.

searchBody.js

 class SearchBody extends Component {
constructor(props) {
      super(props)
      const queryString = require('query-string');
      const queryTerm = queryString.parse(this.props.location.search);
      this.state = { urlSearchTerm: queryTerm.search,
                      searchTerm: '',
                      loaded: false,
                      buttonClicked: null,
                      apiData: [],
                      tableHeaders: [],
                      tableRows: []
                    }
      // check if URL has search term if so pass term for apiCall
      if (this.state.urlSearchTerm) {
         this.state.searchTerm = this.state.urlSearchTerm
      }

      this.handleChange = this.handleChange.bind(this)
      this.handleSubmit = this.handleSubmit.bind(this)
    }


// capture input text field to state variable
handleChange = searchTerm => event => {
  this.setState({ searchTerm: event.target.value })
  //console.log(this.state.searchTerm)
  }

// handle form submission
handleSubmit = (event) => {
  console.log('Inside HandleSubmit')
  console.log('button clicked update url to /?search=' + this.state.searchTerm)
  this.props.history.push('/?search=' + this.state.searchTerm);
  this.setState({buttonClicked: true})
  event.preventDefault();
}
// load search from API if search term is in URL
componentDidMount() {
  console.log('Inside compDidMount')
  if (this.state.urlSearchTerm){
      this.setState({apiData: apiCall(this.state)})
  }
 }

render() {
  const { classes } = this.props;

  let table = ''
  //check if API has loaded data and show results if true
if (this.state.loaded){
  if (this.state.apiData.length === 0 && this.state.buttonClicked){
    table = 'No Results Found'
    //reset search button State
    this.setState({buttonClicked: false})
  } else {
    table = <TableData tableHead={this.state.tableHeaders} tableData={this.state.tableRows} />
    //reset search button State
    this.setState({buttonClicked: false})
  }
}
    return (

      <Fragment>
      <hr/>
       <form /*className={classes.container}*/ noValidate autoComplete="off" onSubmit={this.handleSubmit} >
          <TextField
              id="search"
              label="Search field"
              type="search"
            /*  className={classes.textField}*/
              margin="normal"
              onChange={this.handleChange('search')}
            />
            <Button color='primary' letiant="outlined" type="submit" >Search DB</Button>
        </form>

          <h1>Results: </h1>
              {table}
        </Fragment>
          )
  }

}
export default SearchBody

method.js

// break API data into arry of data for table component rows.
export const parseTableHeaders = input => {
  // console.log(input)
  if (input !== undefined && input.length !== 0) {
  let head = []
  for(let key in input[0]){  head.push(key);}
  //console.log(head)
  return head
}
}

///break API data into array of headers for table component
export const parseTableRows = (input) => {
  let rows = [];
  for(let o in input) {
      rows.push(Object.values(input[o]));
  }
  //console.log(head)
  return rows
}


//get api data from AWS
export function  apiCall(props) {
  const searchTerm = props.searchTerm
  let apigClientFactory = require('aws-api-gateway-client').default;

  const config =  {
                //apiKey: 'xxxx',
                invokeUrl:'https://xxxx.execute-api.us-east-2.amazonaws.com'
                }

  let apigClient = apigClientFactory.newClient(config);
  let params = {
        //This is where any header, path, or querystring request params go. The key is the parameter named as defined in the API
        //  userId: '1234',
        search_keyword: searchTerm
      };
      // Template syntax follows url-template https://www.npmjs.com/package/url-template
  let pathTemplate = '/beta/testDB'
  let method = 'GET';
  let additionalParams = {
      //If there are any unmodeled query parameters or headers that need to be sent with the request you can add them here
      headers: { },
      queryParams: {
        search_keyword: searchTerm
              }
    }
    apigClient.invokeApi(params, pathTemplate, method, additionalParams)
      .then(function(result){
          //This is where you would put a success callback
          console.log('apiCall Returned. searchTerm; ', searchTerm)
          console.log(result)
          props.loaded = true
          props.tableHeaders = parseTableHeaders(JSON.parse(result.data))
          props.tableRows = parseTableRows(JSON.parse(result.data))
          return JSON.parse(result.data)
      }).catch( function(result){
          //This is where you would put an error callback
      })


}

Я неправильно структурировал код?Насколько я понимаю, когда опора меняется, это вызывает повторную визуализацию.Должен ли я передать «this.state.apiData» в apiCall вместо всего состояния, как это?

apiCall(this.state.apiData)

Это выполняется в componentDidMount (). Я считаю, что это правильное местоположение для вызова API, но оно не повторяется при обратном вызове.Я вижу в отладчике, что переменные состояния обновляются, как и ожидалось.Должен ли я установить возвращаемую переменную в apiCall(), и чтобы возвращаемое значение обновляло состояние в componentDidMount ()?Приведет ли это к повторной визуализации после возврата данных?

что-то вроде этого?

this.setState({apiData: apiCall()})

Если я верну this.state.apiData из apiCall () и получу анализ таблицыЗаголовки и строки внутри apiCall, когда возвращается переменная состояния, будет ли это обновление?

Ответы [ 2 ]

0 голосов
/ 22 мая 2018

Эрик Хассельбринг помог мне добраться до этого ответа.Я вызывал apiCall (), и он ничего не возвращал внутри componentDidMount.Я добавил return перед method.js apigClient.invokeAPI (), чтобы он возвращал результат функции

  return apigClient.invokeApi(params, pathTemplate, method, additionalParams)
      .then(function(result){
          //This is where you would put a success callback
          console.log('apiCall Returned. searchTerm; ', searchTerm)
          console.log(result)
          debugger
          props.tableHeaders = parseTableHeaders(JSON.parse(result.data))
          props.tableRows = parseTableRows(JSON.parse(result.data))
          return JSON.parse(result.data)
      }).catch( function(result){
          //This is where you would put an error callback
      })

, затем я обновил свой вызов функции из SearchBody.js до

componentDidMount() {
  console.log('Inside compDidMount')
  if (this.state.urlSearchTerm){
      apiCall(this.state).then(apiResponse => this.setState({
        loaded: true,
        apiData: apiResponse
      })
    )
  }
 }

Итак, теперь apiCall возвращает результат из обещания, а apiCall теперь является обещанием благодаря добавленной функции .then.это позволяет изменять состояние внутри componentDidMount, чтобы при реакции обнаруживалось изменение реквизита, и выполнялся повторный рендеринг.

0 голосов
/ 22 мая 2018

Вы запускаете Async Call, чтобы получить данные API для отдыха.Асинхронный по определению означает, что вы не знаете, когда ваш код закончится.Это означает, что вам понадобится какой-то тип обратного вызова для запуска после завершения вашего apiCall.

Здесь у вас есть вызов API api, который возвращает объект обещания.Объект обещания - это в основном интерфейс для добавления обратных вызовов в асинхронный код.Я рекомендую использовать один из этих вариантов для запуска обратного вызова после вызова restApi.

1.) Вы можете передать функцию обратного вызова в restApi () в качестве второго параметра.Вы бы вызвали этот обратный вызов следующим образом:

let that = this;
apiCall(props, function(result) {
    that.setState({apiData: result});
});

export function  apiCall(props, callback) {
    ...
    apigClient.invokeApi(params, pathTemplate, method, additionalParams)
        .then(function(result){
            ...
            callback(result);
            ...
        });
    ...
}

2.) Другой вариант - обработать разрешение вашего apiCall, фиксируя обещание, которое создается вызовом api.Когда вы выполняете асинхронный код, вызов асинхронного метода немедленно возвращает объект обещания, который вы можете вернуть вызывающей функции, чтобы позволить вызывающей стороне присоединить обратные вызовы.это может показаться немного запутанным, я не лучший в объяснении вещей, но вижу следующее:

let that = this;
apiCall(props).then(function(result) {
    that.setState({apiData: result});
});

export function  apiCall(props) {
    ...
    return apigClient.invokeApi(params, pathTemplate, method, additionalParams)
    .then(function(result){
        ...
    });
}

Ключевое отличие здесь в том, что вы возвращаете фактический асинхронный вызов apigClient.invokeApi.это позволяет любому, кто вызывает apiCall (), присоединять любые функции обратного вызова в методе .then ().

В конечном итоге вы хотите убедиться, что вызываете setState, когда данные restApi фактически возвращаются вызывающей стороне..then () - это самый простой способ вызвать этот вызов и надежно получить возвращенный результат.

Примечание: вы также должны посмотреть на обещания в JS, так как метод .then может принимать 2 параметра: одна функция, которая обрабатывает успешный возврат данных, и одна, которая обрабатывает отчеты об ошибках.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...