我正在尝试传递在React应用程序的一个组件中收到的数据。成功后,我将获取接收的数据并设置状态,然后尝试将该数据作为下一个组件的属性传递。进入第二个组件后,我需要通过this.state
访问传递的数据,以便稍后我可以更改该组件中的状态。在从服务接收数据之前,我似乎遇到了DOM呈现的问题。我已经尝试在this.state.data
中传递已经加载的值数组来代替<List data={this.state.data}/>
,它似乎执行得很好。如何确保在呈现DOM之前我已从服务接收到数据,以便将数据一直传递到每个组件。
编辑:添加了List元素的完整实现,所以解释一下this.state的使用
这基本上就是我想做的事情:
var Box = React.createClass({
getInitialState: function() {
return {data: []};
},
loadTodosFromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
type: 'GET',
cache: false,
success: function(dataResponse) {
this.setState({data: dataResponse});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
componentDidMount: function() {
this.loadFromServer();
},
render: function() {
return (<List data={this.state.data}/>);
}
});
var List = React.createClass({
getInitialState: function() {
return {data: this.props.data};
},
dragStart: function(e) {
this.dragged = e.currentTarget;
e.dataTransfer.effectAllowed = 'move';
// Firefox requires dataTransfer data to be set
e.dataTransfer.setData("text/html", e.currentTarget);
},
dragEnd: function(e) {
this.dragged.style.display = "block";
this.dragged.parentNode.removeChild(placeholder);
// Update data
var data = this.state.data;
var from = Number(this.dragged.dataset.id);
var to = Number(this.over.dataset.id);
if(from < to) to--;
if(this.nodePlacement == "after") to++;
data.splice(to, 0, data.splice(from, 1)[0]);
this.setState({data: data});
},
dragOver: function(e) {
e.preventDefault();
this.dragged.style.display = "none";
if(e.target.className == "placeholder") return;
this.over = e.target;
// Inside the dragOver method
var relY = e.clientY - this.over.offsetTop;
var height = this.over.offsetHeight / 2;
var parent = e.target.parentNode;
if(relY > height) {
this.nodePlacement = "after";
parent.insertBefore(placeholder, e.target.nextElementSibling);
}
else if(relY < height) {
this.nodePlacement = "before"
parent.insertBefore(placeholder, e.target);
}
},
render: function() {
var results = this.state.data;
return (
<ul>
{
results.map(function(result, i) {
return (
<li key={i}>{result}</li>
)
})
}
</ul>
);
}
});
ReactDOM.render(
<Box url="/api/comments"/>, document.getElementById('content')
);
答案 0 :(得分:2)
组件加载后数据加载未呈现数据的原因是List.render函数中的这一行:
var results = this.state.data;
基本上,您已经制作了原始道具的副本,并使用getInitialState方法将它们分配给List组件中的状态。之后你的状态和道具脱钩了。这意味着如果props.data在List组件上发生更改,则状态不会知道它,因此不会重新呈现任何内容。
因此,不使用state来初始化结果变量,而是使用props。
var results = this.props.data
以下是它的样子:
var List = React.createClass({
render: function() {
var results = this.props.data;
return (
<ul>
{
results.map(function(result, i) {
return (
<li key={i}>{result}</li>
)
})
}
</ul>
);
}
});
现在,只要数据发生变化,就会更新道具并最终重新渲染结果。
已更新,以解决OP的评论:
如果您想更新列表的状态但希望每次父级道具更改时都收到通知,那么您希望使用方法componentWillReceiveProps,以便在获取数据时,子列表是收到通知。在这种方法中,您可以设置新状态:
componentWillReceiveProps: function(newProps) {
this.setState({data: this.props.data});
}
执行此操作后,react会为您重新呈现列表。
另一个更新:为了说明这是如何工作的,我将一个例子here放在一起。
这里有JS代码:
let todos = ["Run","Swim","Skate"];
class MyList extends React.Component{
componentWillMount() {
console.log("Props are: ", this.props);
this.setState({list: this.props.items});
}
componentWillReceiveProps(newProps) {
console.log("Received Props are: ", newProps);
this.setState({list: newProps.items});
}
render() {
return (<ul>
{this.state.list.map((todo) => <li>{todo}</li>)}
</ul>);
}
}
class App extends React.Component{
constructor() {
super();
console.log("State is: ", this.state);
}
componentWillMount() {
this.setState({items: ["Fly"]});
}
componentDidMount() {
setTimeout(function(){
console.log("After 2 secs");
this.setState({items: todos});
}.bind(this), 2000);
}
render() {
return (<MyList items={this.state.items}/>);
}
}
ReactDOM.render(<App/>, document.getElementById("app"));