更新React组件共享状态

Update React components sharing state

本文关键字:状态 共享 组件 React 更新      更新时间:2023-09-26

我有两个连接的项目列表。B列表中有复选框。当我取消选中B列表的一个元素时,A列表的相应元素应该被隐藏,但遗憾的是,渲染函数没有被调用。我使用减速器更改应用程序的状态。

我的问题是,在更改状态后不会调用render。由于点击事件由B列表处理,我可以forceUpdate该列表,但A列表将保持不变。

如何处理此连接?

可选链接部分(列表)

import React, { PropTypes, Component } from 'react'
import Link from '../components/Link'
import LinkSelector from '../components/LinkSelector'
import {Popover, OverlayTrigger} from "react-bootstrap"
class SelectableLinksSection extends Component {
    renderPopup() {
        return (
            <Popover id="idea-popup" className="imageP">
                <LinkSelector links={this.props.links} showLink={this.props.showLink} hideLink={this.props.hideLink}/>
            </Popover>
        )
    }
    render() {
        if (this.props.links.length) {
            return (
                <div>
                    <div className="col-sm-7">
                        <div className={this.props.cssClass}>
                            {
                                this.props.links.map(link => {
                                    return <Link url={link.url} label={link.label} icon={link.icon} hide={link.hide}
                                                 text={link.text} widthClass="col-sm-4" dividerClass="divider"/>
                                })
                            }
                        </div>
                    </div>
                    <section className="col-sm-2 no-padding">
                        <div className="col-sm-12">
                            <div className="text-center add">
                                <OverlayTrigger trigger="click" rootClose placement="bottom"
                                                overlay={this.renderPopup()}>
                                    <a role="button" tabIndex="0" title="#i18n:dashboard.ideas.addLink#">
                                    </a>
                                </OverlayTrigger>
                            </div>
                        </div>
                    </section>
                </div>
            )
        } else {
            return <div></div>
        }
    }
}
SelectableLinksSection.propTypes = {
    cdn: PropTypes.string.isRequired,
    title: PropTypes.string.isRequired,
    text: PropTypes.string.isRequired,
    links: PropTypes.array.isRequired,
    cssClass: PropTypes.string.isRequired,
    showLink: PropTypes.func.isRequired,
    hideLink: PropTypes.func.isRequired
}
export default SelectableLinksSection;

链接选择器(B列表)

import React, { PropTypes, Component } from 'react'
import Links from '../components/Links'
class LinkSelector extends Component {
    constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this)
    }
    handleChange(link) {
        if (link.hide) {
            this.props.showLink(link.id)
        } else {
            this.props.hideLink(link.id)
        }
        this.forceUpdate()
    }
    render() {
        return (
            <div className="row">
                {this.props.links.map((link)=> {
                    return (
                        <div key={"link-"+link.id} className="col-sm-3 text-center">
                            <div className="imgContainer"
                                 style={{background:"url('"+link.icon+"') no-repeat center"}}>
                                <input type="checkbox" checked={!link.hide}
                                       onChange={() => {this.handleChange(link)}}/>
                            </div>
                            <div className="title">{link.label}</div>
                        </div>
                    )
                })}
            </div>
        )
    }
}
LinkSelector.propTypes = {
    links: PropTypes.array.isRequired,
    showLink: PropTypes.func.isRequired,
    hideLink: PropTypes.func.isRequired
}
export default LinkSelector;

链接(列表项)

import React, { PropTypes, Component } from 'react'
class Link extends Component {
    render() {
        return (
            <div className={this.props.widthClass} style={this.props.hide ? {display: "none"} : {}}>
                <div className="text-center">
                    <a href={this.props.url}><img alt={this.props.label} src={this.props.icon} /></a>
                </div>
                <div className={this.props.dividerClass}></div>
                <div className="title"><a href={this.props.url}>{this.props.label}</a></div>
                <div className="text" dangerouslySetInnerHTML={{__html: this.props.text}}></div>
            </div>
        )
    }
}
Link.propTypes = {
    label: PropTypes.string.isRequired,
    icon: PropTypes.string.isRequired,
    url: PropTypes.string.isRequired,
    text: PropTypes.string.isRequired,
    hide: PropTypes.bool.isRequired,
    widthClass: PropTypes.string.isRequired,
    dividerClass: PropTypes.string.isRequired
}
export default Link;

[编辑]SectionIdeas(列表容器)

import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux';
import SelectableLinksSection from '../components/SelectableLinksSection'
class SectionIdeas extends Component {
    render() {
        return <SelectableLinksSection title={this.props.title} text={this.props.text} links={this.props.links}
                                       cdn={this.props.cdn} cssClass="row virtual list" showLink={this.props.show} hideLink={this.props.hide} />
    }
}
SectionIdeas.propTypes = {
    cdn: PropTypes.string.isRequired,
    title: PropTypes.string.isRequired,
    text: PropTypes.string.isRequired,
    links: PropTypes.array.isRequired,
    show: PropTypes.func.isRequired,
    hide: PropTypes.func.isRequired
};
function mapStateToProps(state) {
    return {
        cdn: state.data.cdn,
        title: state.data.ideas.title,
        text: state.data.ideas.text,
        links: state.data.ideas.links
    };
}
export default connect(mapStateToProps)(SectionIdeas)

[EDIT]主容器

import React, { Component, PropTypes } from 'react'
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import SectionIdeas from './SectionIdeas'
import { readStateFromServer, setStateToServer } from '../actions/api';
import * as ideasActions from '../actions/ideas';
class App extends Component {
    constructor(props) {
        super(props);
        props.dispatch(readStateFromServer());
    }
    render() {
        const {dispatch} = this.props
        const ideasBoundActions = bindActionCreators(ideasActions, dispatch)
        dispatch(setStateToServer())
        if (this.props.loaded) {
            return (
                <div>
                    <SectionIdeas {...ideasBoundActions} />
                </div>
            )
        } else {
            return (
                <div className="loading">
                    #i18n:Loading#
                </div>
            )
        }
    }
}
App.propTypes = {
    loaded: PropTypes.bool.isRequired,
    dispatch: PropTypes.func.isRequired
};
function mapStateToProps(state) {
    return {
        loaded: state.data.loaded
    };
}
export default connect(mapStateToProps)(App);

[EDIT]操作

export const SHOW = 'SHOW_LINKS'
export const HIDE = 'HIDE_LINKS'
export function show(id) {
    return {
        type: SHOW,
        id: id
    }
}
export function hide(id) {
    return {
        type: HIDE,
        id: id
    }
}

减速器

import { SHOW, HIDE } from '../actions/ideas'
import { RECEIVE_STATE } from '../actions/api'
export default function ideas(state = {}, action = "") {
    switch (action.type) {
        case RECEIVE_STATE:
            return action.json && action.json.data && action.json.data.ideas ? action.json.data.ideas : state
        case SHOW:
            return toggle(state, action.id, true)
        case HIDE:
            return toggle(state, action.id, false)
        default:
            return state
    }
}
function toggle(state, id, show) {
    let newState = Object.assign({}, state)
    newState.links.forEach((link)=> {
        if (link.id === id) {
            link.hide = !show
        }
    })
    return newState
}

州样本

 {
    "title":"Idee per insegnare in digitale",
    "text":"Da qui puoi consultare siti di approfondimento",
    "links":[
        {
            "id":1,
            "icon":"http:'/'/cdn-my.zanichelli.local'/fe'/images'/dashboard'/spazio-clil.png",
            "url":"http:'/'/online.scuola.zanichelli.it'/spazioclil'/",
            "label":"Spazio CLIL",
            "text":"",
            "hide":false
        },
        {
            "id":2,
            "icon":"http:'/'/cdn-my.zanichelli.local'/fe'/images'/dashboard'/invalsi-myzanichelli.png",
            "url":"http:'/'/online.scuola.zanichelli.it'/quartaprova'/",
            "label":"Invalsi",
            "text":"",
            "hide":false
        },
        {
            "id":3,
            "icon":"http:'/'/cdn-my.zanichelli.local'/fe'/images'/dashboard'/aula-scienze-myzanichelli.png",
            "url":"http:'/'/aulascienze.scuola.zanichelli.it'/",
            "label":"Aula di Scienze",
            "text":"",
            "hide":false
        },
        {
            "id":4,
            "icon":"http:'/'/cdn-my.zanichelli.local'/fe'/images'/dashboard'/guida-myzanichelli.png",
            "url":"http:'/'/altro.scuola.zanichelli.it",
            "label":"Altro",
            "text":"",
            "hide":true
        }
    ]
}

一个可能的解决方案(希望不是最好的解决方案)是将handleChange函数从LinkSelector组件(B List)移动到其父SelectableLinksSection(它也包含A List),并将该函数作为属性传递给LinkSelector。通过这种方式,forceUpdate函数强制两个列表的渲染方法