Reactjs 反应:更新数组中的组件

Reactjs 反应:更新数组中的组件,reactjs,Reactjs,我有一个React组件,它包含一系列子组件。父级从服务检索数据并将其存储在状态。它通过道具将数据数组中的一项传递给每个子组件 子组件包括更新其数据项中的值的功能。当它执行此操作时,会触发一个事件,将更新的项传递回父项。父级创建一个新的状态数组,包括更新的项 下面是简化的代码 这一切都很好,更新数组在父级的渲染方法中处理。但是,子组件永远不会重新渲染,因此更新的属性将保持其以前的值 如何使相关子组件显示更新的状态 class SearchView extends Component { p

我有一个React组件,它包含一系列子组件。父级从服务检索数据并将其存储在状态。它通过道具将数据数组中的一项传递给每个子组件

子组件包括更新其数据项中的值的功能。当它执行此操作时,会触发一个事件,将更新的项传递回父项。父级创建一个新的状态数组,包括更新的项

下面是简化的代码

这一切都很好,更新数组在父级的渲染方法中处理。但是,子组件永远不会重新渲染,因此更新的属性将保持其以前的值

如何使相关子组件显示更新的状态

class SearchView extends Component {
    pageSize = 20;

    constructor(props) {
        super(props);
        this.state = { 
            searchTerm: this.props.searchTerm, 
            results: []
        };                
    }

    getResults = (page) => {  
        const from = (page - 1) * this.pageSize;
        searchActions.termSearch(this.state.searchTerm, from, this.pageSize).then(response => { 
            const results = response.SearchResultViews;
            this.setState({ 
                results: results
            });
        });    
    }

    componentDidMount() {
        this.getResults(1);
    }

    refresh(result){
        const results = this.state.results.map(r => {
            return (r.Id === result.Id) ? result : r;
        });
        this.setState({
            results: results
        });
    }

    render() {
        let items = [];
        if (this.state.results.length > 0) {
            items = this.state.results.map((result, i) => {
                return <SearchItem key={i} result={result} onStatusUpdate={(r) => this.refresh(r)}></SearchItem>;
            });    
        }

        return (
            <div className="r-search-result">
                <Row className='clearfix scroller'>                        
                    <div className='r-container-row results'>        
                        { items }
                    </div>
                </Row>
            </div>
        );
    }
}

class SearchItem extends Component {
    constructor(props) {
        super(props);
    }

    updateStatus(newValue) {
        resourceActions.updateStatus(newValue);
        //Bubble an event to the Parent to refresh the result and view   
        if (props.onStatusUpdate) {
            searchActions.get(props.result.Id).then((result) => {
                props.onStatusUpdate(result);
            });    
        }
    }

    render() {
        return (                                    
            <a href={this.props.result.link}>
                <span className="column icon-column">{this.props.result.imageUrl}</span>
                <span className="column title-column">{this.props.result.titleLink}</span>
                <span className="column status-column">{this.props.result.status}</span>
                <span className="column button-column"><button onClick={() => this.UpdateStatus(5)}></button></span>
            </a>
        );
    }
}
类SearchView扩展组件{
页面大小=20;
建造师(道具){
超级(道具);
this.state={
searchTerm:this.props.searchTerm,
结果:[]
};                
}
getResults=(第页)=>{
const from=(第1页)*this.pageSize;
searchActions.termSearch(this.state.searchTerm,from,this.pageSize)。然后(response=>{
const results=response.searchresultview;
这个.setState({
结果:结果
});
});    
}
componentDidMount(){
这是结果(1);
}
刷新(结果){
constresults=this.state.results.map(r=>{
返回(r.Id==result.Id)?结果:r;
});
这是我的国家({
结果:结果
});
}
render(){
设项目=[];
如果(this.state.results.length>0){
items=this.state.results.map((result,i)=>{
返回这个。刷新(r)}>;
});    
}
返回(
{items}
);
}
}
类SearchItem扩展组件{
建造师(道具){
超级(道具);
}
更新状态(新值){
resourceActions.updateStatus(newValue);
//将事件冒泡到父级以刷新结果和视图
如果(道具状态更新){
searchActions.get(props.result.Id)。然后((result)=>{
道具状态更新(结果);
});    
}
}
render(){
报税表(
);
}
}
编辑 在我的实际(非简化)应用程序中,子组件转换在
ComponentDidMount()
方法中传递的道具,并在状态中设置值;render方法将标记绑定到state,而不是props。按照@Vishal在注释中的建议,在子级的
Render()
方法中放置断点后,我可以看到子级收到了更新的数据,但由于状态尚未更新,因此组件不会显示更新的数据


接下来的问题是,如何在不导致无限渲染循环的情况下最好地更新组件状态

最后,我通过在
componentWillUpdate()
中将子组件的属性转换为状态,以及
componentDidMount()
方法,解决了这个问题。如以下代码所示:

componentDidMount() {
    if (this.props.result) {
        this.prepareRender();
    }
}

componentWillUpdate(nextProps, nextState) {
    if (nextProps.result.status!== this.props.result.status) {
        this.prepareRender();
    }
}

prepareRender() {
    //simplified
    this.setState({
        imageUrl: this.props.result.imageUrl,
        titleLink: this.props.result.titleLink,
        status: this.props.result.status
    });
}

render() {
    return (                                    
        <a href={this.props.result.link}>
            <span className="column icon-column">{this.state.imageUrl}</span>
            <span className="column title-column">{this.state.titleLink}</span>
            <span className="column status-column">{this.state.status}</span>
            <span className="column button-column"><button onClick={() => this.UpdateStatus(5)}></button></span>
        </a>
    );
}
componentDidMount(){
如果(此.props.result){
这个.prepareRender();
}
}
组件将更新(下一步,下一步状态){
if(nextrops.result.status!==this.props.result.status){
这个.prepareRender();
}
}
制备程序(){
//简化
这是我的国家({
imageUrl:this.props.result.imageUrl,
titleLink:this.props.result.titleLink,
状态:this.props.result.status
});
}
render(){
报税表(
);
}
更新


在React 16.3中,不推荐使用
componentWillUpdate()
方法。此解决方案应使用新的
getDerivedStateFromProps()
生命周期方法,如下所述:。

您确定在SearchItem中承诺随后得到执行(并调用props.onStatusUpdate)?是的,所有工作都按计划进行。如果在refresh/render方法期间在子组件构造函数中放置断点,它将永远不会被调用,子组件的构造函数将只被调用一次。只需在child.ok的render方法上设置一个断点!这就解释了一些事情!