Реагировать на выборку данных на сервере перед рендерингом
Я новичок в реакции, я хочу получить данные на сервере, чтобы он отправил страницу с данными клиенту.
Это нормально, когда функция getDefaultProps возвращает фиктивные данные, подобные этому {data: {books: [{..}, {..}]}}.
Однако не работает с кодом ниже. Код выполняется в этой последовательности с сообщением об ошибке "Невозможно прочитать свойства" книги "undefined"
- getDefaultProps
- возвращение
- извлечь
- {data: {books: [{..}, {..}]}}
Однако, я ожидаю, что код должен работать в этой последовательности
- getDefaultProps
- извлечь
- {data: {books: [{..}, {..}]}}
- возвращение
Любая идея?
statics: {
fetchData: function(callback) {
var me = this;
superagent.get('http://localhost:3100/api/books')
.accept('json')
.end(function(err, res){
if (err) throw err;
var data = {data: {books: res.body} }
console.log('fetch');
callback(data);
});
}
getDefaultProps: function() {
console.log('getDefaultProps');
var me = this;
me.data = '';
this.fetchData(function(data){
console.log('callback');
console.log(data);
me.data = data;
});
console.log('return');
return me.data;
},
render: function() {
console.log('render book-list');
return (
<div>
<ul>
{
this.props.data.books.map(function(book) {
return <li key={book.name}>{book.name}</li>
})
}
</ul>
</div>
);
}
Ответы
Ответ 1
То, что вы ищете, это componentWillMount
.
Из документации:
Вызывается один раз, как на клиенте, так и на сервере, непосредственно перед происходит первоначальный рендеринг. Если вы вызываете setState
в этом методе, render()
будет видеть обновленное состояние и будет выполняться только один раз несмотря на изменение состояния.
Итак, вы сделали бы что-то вроде этого:
componentWillMount : function () {
var data = this.getData();
this.setState({data : data});
},
Таким образом, render()
будет вызываться только один раз, и у вас будут данные, которые вы ищете в первоначальном рендере.
Ответ 2
В реакторе props
используются для параметров компонента, не предназначенных для обработки данных. Существует отдельная конструкция для state
. Всякий раз, когда вы обновляете state
, компонент в основном повторно отображает себя в соответствии с новыми значениями.
var BookList = React.createClass({
// Fetches the book list from the server
getBookList: function() {
superagent.get('http://localhost:3100/api/books')
.accept('json')
.end(function(err, res) {
if (err) throw err;
this.setBookListState(res);
});
},
// Custom function we'll use to update the component state
setBookListState: function(books) {
this.setState({
books: books.data
});
},
// React exposes this function to allow you to set the default state
// of your component
getInitialState: function() {
return {
books: []
};
},
// React exposes this function, which you can think of as the
// constructor of your component. Call for your data here.
componentDidMount: function() {
this.getBookList();
},
render: function() {
var books = this.state.books.map(function(book) {
return (
<li key={book.key}>{book.name}</li>
);
});
return (
<div>
<ul>
{books}
</ul>
</div>
);
}
});
Ответ 3
Лучший ответ, который я использую для получения данных с сервера и отображения его
constructor(props){
super(props);
this.state = {
items2 : [{}],
isLoading: true
}
}
componentWillMount (){
axios({
method: 'get',
responseType: 'json',
url: '....',
})
.then(response => {
self.setState({
items2: response ,
isLoading: false
});
console.log("Asmaa Almadhoun *** : " + self.state.items2);
})
.catch(error => {
console.log("Error *** : " + error);
});
})}
render() {
return(
{ this.state.isLoading &&
<i className="fa fa-spinner fa-spin"></i>
}
{ !this.state.isLoading &&
//external component passing Server data to its classes
<TestDynamic items={this.state.items2}/>
}
) }
Ответ 4
В качестве дополнения к ответу Майкла Паркера вы можете заставить getData принять функцию обратного вызова для активации setState обновить данные:
componentWillMount : function () {
var data = this.getData(()=>this.setState({data : data}));
},
Ответ 5
Очень простой пример этого
import React, { Component } from 'react';
import { View, Text } from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data : null
};
}
componentWillMount() {
this.renderMyData();
}
renderMyData(){
fetch('https://your url')
.then((response) => response.json())
.then((responseJson) => {
this.setState({ data : responseJson })
})
.catch((error) => {
console.error(error);
});
}
render(){
return(
<View>
{this.state.data ? <MyComponent data={this.state.data} /> : <MyLoadingComponnents /> }
</View>
);
}
}
Ответ 6
Отвечая на аналогичный вопрос с потенциально простым решением этого, если кто-то все еще находится после ответа, уловка связана с использованием сокращений-саг:
fooobar.com/info/312721/...
Или просто перейдите прямо к статье, которую я написал по теме:
https://medium.com/@navgarcha7891/react-server-side-rendering-with-simple-redux-store-hydration-9f77ab66900a