更新React组件共享状态
Update React components sharing state
我有两个连接的项目列表。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
函数强制两个列表的渲染方法
相关文章:
- 在Knockoutjs中的ViewModels之间共享变量状态
- new Datamap() 在调用之间保持内存的共享状态
- 在角度上不同控制器之间共享状态
- 如何通过React Native中的组件共享登录状态
- JavaScript-使用sessionStorage保存文档之间共享的复选框状态
- 正在加载ui路由器状态下的共享模型
- Ember JS中控制器之间共享状态的正确方式
- 如果我两次使用相同的反应/冗余组件,它们会共享状态吗?
- 使用工厂时控制器/模板不共享相同的状态
- 摩卡测试共享状态,因为范围不好
- ui路由器——具有一条路由'的URL与另一个具有$stateParams的状态共享同一级别
- 更新React组件共享状态
- 如何在没有闭包的情况下对共享状态进行编程
- 在ui路由器中的状态之间共享ng模型数据
- 在控制器之间共享非单例状态(Angular Architecture)
- 在子组件之间共享父组件状态'州
- 保存公用共享的值状态(添加到URL)
- 如何在angularjs中使用两个不同的ui路由器在状态之间共享作用域数据?
- 当ui-router状态改变时,清除AngularJS共享控制器变量
- 使用AMD和Backbone在模块之间共享对象(或状态)的干净方法