Javascript 两个组件进行通信
我刚开始使用ReactJS,有点被我遇到的一个问题所困扰 我的应用程序本质上是一个带有过滤器的列表和一个用来更改布局的按钮。 目前我正在使用三个组件:Javascript 两个组件进行通信,javascript,reactjs,Javascript,Reactjs,我刚开始使用ReactJS,有点被我遇到的一个问题所困扰 我的应用程序本质上是一个带有过滤器的列表和一个用来更改布局的按钮。 目前我正在使用三个组件:、和,显然,当我更改中的设置时,我想触发中的某些方法来更新我的视图 我如何使这三个组件相互交互,或者我需要某种全局数据模型,以便对其进行更改?最佳方法取决于您计划如何安排这些组件。现在想到的几个示例场景: 是 和都是父组件的子组件 和完全位于单独的根组件中 可能还有其他我没有想到的情况。如果你的不适合这些,请告诉我。以下是我如何处理前两个场景的一些
、
和
,显然,当我更改
中的设置时,我想触发
中的某些方法来更新我的视图
我如何使这三个组件相互交互,或者我需要某种全局数据模型,以便对其进行更改?最佳方法取决于您计划如何安排这些组件。现在想到的几个示例场景:
是
和
都是父组件的子组件
和
完全位于单独的根组件中
传递到
,然后在onChange
事件上调用该处理程序,以使用当前值筛选列表
/**@jsx React.DOM*/
var Filters=React.createClass({
handleFilterChange:函数(){
var value=this.refs.filterInput.getDOMNode().value;
this.props.updateFilter(值);
},
render:function(){
返回;
}
});
var List=React.createClass({
getInitialState:函数(){
返回{
清单项目:[“芝加哥”、“纽约”、“东京”、“伦敦”、“旧金山”、“阿姆斯特丹”、“香港”],
名称筛选器:“”
};
},
handleFilterUpdate:函数(filterValue){
这是我的国家({
nameFilter:filterValue
});
},
render:function(){
var displayedItems=this.state.listItems.filter(函数(项){
var match=item.toLowerCase().indexOf(this.state.nameFilter.toLowerCase());
返回(匹配!=-1);
}.约束(这个);
var含量;
如果(displayedItems.length>0){
var items=displayedItems.map(函数(项){
返回{item} ;
});
内容={items}
}否则{
内容=没有与此筛选器匹配的项目;
}
返回(
结果
{content}
);
}
});
React.renderComponent(,document.body);
情景2 与场景#1类似,但父组件将把处理程序函数传递给
,并将过滤列表传递给
。我更喜欢这种方法,因为它将
与
分离
/**@jsx React.DOM*/
var Filters=React.createClass({
handleFilterChange:函数(){
var value=this.refs.filterInput.getDOMNode().value;
this.props.updateFilter(值);
},
render:function(){
返回;
}
});
var List=React.createClass({
render:function(){
var含量;
如果(this.props.items.length>0){
var items=this.props.items.map(函数(项){
返回{item} ;
});
内容={items}
}否则{
内容=没有与此筛选器匹配的项目;
}
返回(
结果
{content}
);
}
});
var ListContainer=React.createClass({
getInitialState:函数(){
返回{
清单项目:[“芝加哥”、“纽约”、“东京”、“伦敦”、“旧金山”、“阿姆斯特丹”、“香港”],
名称筛选器:“”
};
},
handleFilterUpdate:函数(filterValue){
这是我的国家({
nameFilter:filterValue
});
},
render:function(){
var displayedItems=this.state.listItems.filter(函数(项){
var match=item.toLowerCase().indexOf(this.state.nameFilter.toLowerCase());
返回(匹配!=-1);
}.约束(这个);
返回(
);
}
});
React.renderComponent(,document.body);
情景3
当组件无法在任何类型的父子关系之间通信时,.这就是我处理此问题的方式。
假设你有一个月和一天。 天数取决于所选月份 这两个列表都属于第三个对象,即左侧面板。两者都是leftPanel的子级
这是一个在LeftPanel组件中包含回调和处理程序的游戏 要测试它,只需将代码复制到两个单独的文件中,然后运行index.html。然后选择一个月,看看天数是如何变化的 dates.js
/**@jsx React.DOM*/
var monthsLength=[0,31,28,31,30,31,31,30,31,30,31];
var月数=月数[“一月”、“二月”、“三月”、“四月”、“五月”、“六月”、“七月”、“八月”、“九月”、“十月”、“十一月”、“十二月];
var DayNumber=React.createClass({
render:function(){
返回(
{this.props.dayNum}
);
}
});
var DaysList=React.createClass({
getInitialState:函数(){
返回{numOfDays:30};
},
handleMonthUpdate:函数(newMonthix){
this.state.numOfDays=monthsLength[newMonthix];
console.log(“将天数设置为”+monthLength[newMonthix]+“month=“+newMonthix”);
这个.forceUpdate();
},
HandleDay选择:功能(evt){
this.props.dateHandler(evt.target.value);
},
componentDidMount:function(){
this.props.readyCallback(this.handleMonthUpdate)
},
render:function(){
var dayNodes=[];
对于(i=1;i来说,有多种方法可以使组件进行通信。有些方法可以适合您的用例。下面是一些我认为有用的方法的列表
反应
亲子直接沟通
<
const Child = ({fromChildToParentCallback}) => (
<div onClick={() => fromChildToParentCallback(42)}>
Click me
</div>
);
class Parent extends React.Component {
receiveChildValue = (value) => {
console.log("Parent received value from child: " + value); // value is 42
};
render() {
return (
<Child fromChildToParentCallback={this.receiveChildValue}/>
)
}
}
const AppContext = React.createContext(null)
class App extends React.Component {
render() {
return (
<AppContext.Provider value={{language: "en",userId: 42}}>
<div>
...
<SomeDeeplyNestedComponent/>
...
</div>
</AppContext.Provider>
)
}
};
const SomeDeeplyNestedComponent = () => (
<AppContext.Consumer>
{({language}) => <div>App language is currently {language}</div>}
</AppContext.Consumer>
);
<div className="a">
a content
<Portal target="body">
<div className="b">
b content
</div>
</Portal>
</div>
<body>
<div id="reactAppContainer">
<div className="a">
a content
</div>
</div>
<div className="b">
b content
</div>
</body>
import { Slot, Fill } from 'react-slot-fill';
const Toolbar = (props) =>
<div>
<Slot name="ToolbarContent" />
</div>
export default Toolbar;
export const FillToolbar = ({children}) =>
<Fill name="ToolbarContent">
{children}
</Fill>
<AltContainer stores={{
SidebarStore: SidebarStore
}}>
<Sidebar/>
</AltContainer>
{this.props.content}
class SiteActions {
constructor() {
this.generateActions(
'setSiteComponentStore'
);
}
setSiteComponent(value) {
this.dispatch({value: value});
}
}
class SiteStore {
constructor() {
this.siteComponents = {
Prop: true
};
this.bindListeners({
setSiteComponent: SidebarActions.COMPONENT_STATUS_CHANGED
})
}
setSiteComponent(data) {
this.siteComponents.Prop = data.value;
}
}
componentStatusChanged(value){
this.dispatch({value: value});
}
constructor() {
this.structures = [];
this.bindListeners({
componentStatusChanged: SidebarActions.COMPONENT_STATUS_CHANGED
})
}
componentStatusChanged(data) {
this.waitFor(DetailsStore);
_.findWhere(this.structures[0].elem, {title: 'Example'}).enabled = data.value;
}
<div>
<List items={this.state.filteredItems}/>
<Filter filter={this.state.filter} setFilter={setFilter}/>
</div>
import React, {Component} from 'react';
import {render} from 'react-dom';
const Person = ({person, setForDelete}) => (
<div>
<input type="checkbox" name="person" checked={person.checked} onChange={setForDelete.bind(this, person)} />
{person.name}
</div>
);
class PeopleList extends Component {
render() {
return(
<div>
{this.props.people.map((person, i) => {
return <Person key={i} person={person} setForDelete={this.props.setForDelete} />;
})}
<div onClick={this.props.deleteRecords}>Delete Selected Records</div>
</div>
);
}
} // end class
class App extends React.Component {
constructor(props) {
super(props)
this.state = {people:[{id:1, name:'Cesar', checked:false},{id:2, name:'Jose', checked:false},{id:3, name:'Marbel', checked:false}]}
}
deleteRecords() {
const people = this.state.people.filter(p => !p.checked);
this.setState({people});
}
setForDelete(person) {
const checked = !person.checked;
const people = this.state.people.map((p)=>{
if(p.id === person.id)
return {name:person.name, checked};
return p;
});
this.setState({people});
}
render () {
return <PeopleList people={this.state.people} deleteRecords={this.deleteRecords.bind(this)} setForDelete={this.setForDelete.bind(this)}/>;
}
}
render(<App/>, document.getElementById('app'));
class App extends React.Component<IAppProps, IAppState> {
private _navigationPanel: NavigationPanel;
private _mapPanel: MapPanel;
constructor() {
super();
this.state = {};
}
// `componentDidMount()` is called by ReactJS after `render()`
componentDidMount() {
// Pass _mapPanel to _navigationPanel
// It will allow _navigationPanel to call _mapPanel directly
this._navigationPanel.setMapPanel(this._mapPanel);
}
render() {
return (
<div id="appDiv" style={divStyle}>
// `ref=` helps to get reference to a child during rendering
<NavigationPanel ref={(child) => { this._navigationPanel = child; }} />
<MapPanel ref={(child) => { this._mapPanel = child; }} />
</div>
);
}
}