admin管理员组文章数量:1421263
I have this ponent class (and some related methods):
const sortData = (name, data) => {
return data.sort((a, b) => {return b[name] - a[name]});
};
class LeaderTable extends React.Component {
renderByRecent() {
let data = sortData('recent', this.props.list);
ReactDOM.render(
<LeaderTable list={data}/>,
document.getElementById('board'))
}
render() {
return (
<table className="table table-bordered">
<thead>
<tr>
<td><strong>#</strong></td>
<td><strong>Camper Name</strong></td>
<td id="recent" onClick={() => this.renderByRecent()} className="text-center">Points in past 30 days</td>
<td id="alltime" onClick={() => this.render()} className="text-center">All time points</td>
</tr>
</thead>
<tbody>
{this.props.list.map(function(item, index) {
let url = "/" + item.username;
return (
<tr key={index}>
<td>{index}</td>
<td>
<a href={url}>
<img src={item.img} className="logo"/> {item.username}
</a>
</td>
<td className="text-center">{item.recent}</td>
<td className="text-center">{item.alltime}</td>
</tr>
);
})}
</tbody>
</table>
);
}
}
Now first render happens when page loads. It is simply called in javascript file like this:
ReactDOM.render(
<LeaderTable list={campersData}/>,
document.getElementById('board'))
This one is working fine.
What I need now is to rerender same ponent, but with different data (actually just with different order of that data).
If you look into renderByRecent
method, here I "rerender" by passing same data sorted in different way (and is is called using onClick
on td
with id='"recent"
. But I do not know if this is really a good pattern to rerender.
Also I want to rerender back original data if td
with id="alltime"
is clicked. This part seems to not work (It does call render
method every time I press respective td
, but nothing changes). I guess I can't recal render
method and hope to rerender
it?
What kind of pattern is usually done with react if you have some similar case like this?
Update
Posted my original code on codepen, for easier investigation:
I have this ponent class (and some related methods):
const sortData = (name, data) => {
return data.sort((a, b) => {return b[name] - a[name]});
};
class LeaderTable extends React.Component {
renderByRecent() {
let data = sortData('recent', this.props.list);
ReactDOM.render(
<LeaderTable list={data}/>,
document.getElementById('board'))
}
render() {
return (
<table className="table table-bordered">
<thead>
<tr>
<td><strong>#</strong></td>
<td><strong>Camper Name</strong></td>
<td id="recent" onClick={() => this.renderByRecent()} className="text-center">Points in past 30 days</td>
<td id="alltime" onClick={() => this.render()} className="text-center">All time points</td>
</tr>
</thead>
<tbody>
{this.props.list.map(function(item, index) {
let url = "https://www.freecodecamp./" + item.username;
return (
<tr key={index}>
<td>{index}</td>
<td>
<a href={url}>
<img src={item.img} className="logo"/> {item.username}
</a>
</td>
<td className="text-center">{item.recent}</td>
<td className="text-center">{item.alltime}</td>
</tr>
);
})}
</tbody>
</table>
);
}
}
Now first render happens when page loads. It is simply called in javascript file like this:
ReactDOM.render(
<LeaderTable list={campersData}/>,
document.getElementById('board'))
This one is working fine.
What I need now is to rerender same ponent, but with different data (actually just with different order of that data).
If you look into renderByRecent
method, here I "rerender" by passing same data sorted in different way (and is is called using onClick
on td
with id='"recent"
. But I do not know if this is really a good pattern to rerender.
Also I want to rerender back original data if td
with id="alltime"
is clicked. This part seems to not work (It does call render
method every time I press respective td
, but nothing changes). I guess I can't recal render
method and hope to rerender
it?
What kind of pattern is usually done with react if you have some similar case like this?
Update
Posted my original code on codepen, for easier investigation: https://codepen.io/andriusl/pen/YxWXzg
Share Improve this question edited Aug 1, 2017 at 16:48 Andrius asked Aug 1, 2017 at 16:20 AndriusAndrius 21.2k47 gold badges154 silver badges264 bronze badges4 Answers
Reset to default 2is really a good pattern to re-render?
I think no, if you want to render same ponent with different data manage that by using state variable don't use ReactDOM.render
again.
Either use a state variable that will save the key name by which you want to sort the data then during ui creating check that and sort the data, Or you can store the props data in state variable and modify that data.
Issue with syntax
onClick={() => this.render()}
:
As per DOC:
The problem with this syntax is that a different callback is created each time the ponent renders, so better to bind the method in the constructor.
Issue with this.render():
Calling render
method is not a good idea, always do setState
react will automatically re-render the ponent.
You can write the code like this:
const sortData = (name, data) => {
return data.sort((a, b) => b[name] - a[name]);
};
class LeaderTable extends React.Component {
constructor(){
super();
this.state = {
sortBy: ''
}
}
_renderList(){
let data = this.props.list.slice(0);
if(this.state.sortBy){
data = sortData(this.state.sortBy, data);
}
return data.map(function(item, index) {
let url = "https://www.freecodecamp./" + item.username;
return (
<tr key={index}>
<td>{index}</td>
<td>
<a href={url}>
<img src={item.img} className="logo"/> {item.username}
</a>
</td>
<td className="text-center">{item.recent}</td>
<td className="text-center">{item.alltime}</td>
</tr>
);
});
}
renderByRecent() {
this.setState({
sortBy: 'recent'
});
}
renderOriginalList(){
this.setState({
sortBy: ''
});
}
render() {
return (
<table className="table table-bordered">
<thead>
<tr>
<td><strong>#</strong></td>
<td><strong>Camper Name</strong></td>
<td id="recent" onClick={() => this.renderByRecent()} className="text-center">Points in past 30 days</td>
<td id="alltime" onClick={() => this.renderOriginalList()} className="text-center">All time points</td>
</tr>
</thead>
<tbody>
{this._renderList()}
</tbody>
</table>
);
}
}
You should only have one main render method. Mount the React ponent to the DOM outside of your ponent and let React manage controlling the DOM updates as the ponent state changes.
corrected pin codepen
class LeaderTable extends React.Component {
constructor() {
super();
this.state = {
sort: false
};
this.renderByRecent = this.renderByRecent.bind(this); // bind this context to method
}
renderByRecent() {
let data = this.props.list.slice();
if (this.state.sort) {
data.sort((a, b) => {
return b.recent - a.recent;
});
}
return data.map(function(item, index) {
let url = "https://www.freecodecamp./" + item.username;
return (
<tr key={index}>
<td>
{index}
</td>
<td>
<a href={url}>
<img src={item.img} className="logo" />{" "}
{item.username}
</a>
</td>
<td className="text-center">
{item.recent}
</td>
<td className="text-center">
{item.alltime}
</td>
</tr>
);
});
}
render() {
return (
<table className="table table-bordered">
<thead>
<tr>
<td>
<strong>#</strong>
</td>
<td>
<strong>Camper Name</strong>
</td>
<td
id="recent"
onClick={() => this.setState({ sort: true })}
className="text-center"
>
Points in past 30 days
</td>
<td
id="alltime"
onClick={() => this.setState({ sort: false })}
className="text-center"
>
All time points
</td>
</tr>
</thead>
<tbody>
{this.renderByRecent()}
</tbody>
</table>
);
}
}
ReactDOM.render(<LeaderTable list={data} />, document.getElementById("board"));
I have a few suggestions, first of all .sort()
works in-place
meaning that you are mutating the data you are trying to sort. For this reason I prefer to do a .slice()
first then .sort()
. This will return a new array sorted according to any sorting function you pass in, not mutating data is a good functional programming practice. Regarding a good approach, it depends on how you manage your state, but in general the need to force an update (from my experience) indicates you should reconsider your logic, I would only force an update as last resort.
If you normally manage your state inside the ponent I would save the data into a state variable, then have different methods that sort that data according to my needs. To give you a brief example:
...
constructor(props) {
super(props);
this.state = { listData: this.props.list };
this.sortBy = this.sortBy.bind(this);
}
sortBy(field) {
const { listData } = this.state;
const sortedList = listData
.slice()
.sort((a,b) => b[field] - a[field]);
this.setState({ listData: sortedList });
}
render() {
return (
<div>
{this.state.listData.map(listItem => <MyComponent ...listItem />)}
<button onClick={() => this.sortBy('recent')}>Sort by recent</button>
<button onClick={() => this.sortBy('alltime)}>Sort by all time</button>
</div>
)
}
...
EDIT
Although you already accepted an answer, check out this implementation, which I find easier to read and maintain. It also provides a more reusable sorting approach.
React will automatically re-render if the props ing into the ponent have changed. So the sorting should be happening on the higher level ponent that is passing props to this one. You should also not be mutating the props like that.
You could also have this ponent manage the list in its own state like so:
const sortData = (name, data) => {
return data.sort((a, b) => {return b[name] - a[name]});
};
class LeaderTable extends React.Component {
constructor(props) {
super(props)
this.state={
list: [{ name: 'Jerry'}, {name: 'Tabitha'}]
}
}
renderByRecent() {
// spread the array so it doesn't mutate state
this.setState({
list: sortData('name', [...this.state.list])
})
}
render() {
return (
<table className="table table-bordered">
<thead>
<tr>
<td><strong>#</strong></td>
<td><strong>Camper Name</strong></td>
<td id="recent" onClick={() => this.renderByRecent()} className="text-center">Points in past 30 days</td>
<td id="alltime" onClick={() => this.render()} className="text-center">All time points</td>
</tr>
</thead>
<tbody>
{this.state.list.map(function(item, index) {
let url = "https://www.freecodecamp./" + item.username;
return (
<tr key={index}>
<td>{index}</td>
<td>
<a href={url}>
<img src={item.img} className="logo"/> {item.username}
</a>
</td>
<td className="text-center">{item.recent}</td>
<td className="text-center">{item.alltime}</td>
</tr>
);
})}
</tbody>
</table>
);
}
}
本文标签: javascriptReactJSrerender same component with different dataStack Overflow
版权声明:本文标题:javascript - ReactJS - rerender same component with different data? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745344325a2654408.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论