我终于得到了一个实际有效的响应式设置。但我非常希望得到一些关于这是一个好的设置和数据流的反馈。
我做了以下事情:
import React, { Component } from 'react';
import './App.css';
import AB_eval from './components/AB_eval';
class App extends Component {
constructor() {
super();
this.updateDB = this.updateDB.bind(this);
// getInitialState
this.state = {
DB: []
};
}
updateDB(k, bar) {
const DB = {...this.state.DB}
DB[k] = bar;
this.setState({ DB });
}
render() {
return (
<div className="App">
<AB_eval A={2} B={3} updateDB={this.updateDB} />
</div>
);
}
}
export default App;
import React, { Component } from 'react';
import Slider from 'react-rangeslider';
class AB_eval extends Component {
constructor(props, context){
super(props, context);
this.updateDB = this.updateDB.bind(this);
this.refreshAB = this.refreshAB.bind(this);
let {A, B} = this.props;
let AB = A * B;
this.state = {
A: A,
B: B,
AB: AB
}
}
componentDidMount () {
this.updateDB();
}
refreshAB () {
const AB = this.state.A * this.state.B;
this.setState({
AB: AB
});
}
updateDB () {
const bar = {
A: this.state.A,
B: this.state.B,
AB: this.state.AB
}
this.props.updateDB(0, bar) // updating the App's state
}
render() {
let {A, B, AB} = this.state;
return (
<div>
<h1>AB_eval: {AB}</h1>
<h2>A</h2>
<p>A: {A} B: {B} AB:{AB}</p>
<Slider min={1} max={4} step={1}
value={A}
onChange={ (value)=> {
this.setState({
A: value
});
this.refreshAB()
this.updateDB() }
}
/>
<h2>B</h2>
<p>A: {A} B: {B} AB:{AB}</p>
<Slider min={1} max={4} step={1}
value={B}
onChange={ (value)=> {
this.setState({
B: value
});
this.refreshAB()
this.updateDB() }
}
/>
</div>
)
}
}
AB_eval.propTypes = {
A: React.PropTypes.number.isRequired,
B: React.PropTypes.number.isRequired,
updateDB: React.PropTypes.func.isRequired
};
export default AB_eval;
接下来是添加C滑块 - 因此它将成为ABC_eval。但首先我需要知道:
App和AB_eval之间的数据流是一种好方法吗?
将内容分解为更多组件是否有意义?
我意识到在setState
组件中使用AB_eval
在循环遍历状态之后并不是一个好主意。
我将代码更新为以下内容,但它不起作用..想想我错过了几件事情。
module.exports = {
one: {A: 1,
B: 2,
AB: 2
},
two: { A: 3,
B: 4,
AB: 12
}
};
import React, { Component } from 'react';
import './App.css';
import AB_eval from './components/AB_eval';
import dummyData from './dummy-data';
class App extends Component {
constructor() {
super();
this.updateDB = this.updateDB.bind(this);
// getInitialState
this.state = {
DB: dummyData
};
}
updateDB(key, bar) {
const DB = {...this.state.DB}
DB[key] = bar;
this.setState({ DB });
}
render() {
return (
<div className="App">
<ul className="list-of-ABs">
{ Object
.keys(this.state.DB)
.map(key =>
<AB_eval
key = {key}
ID = {key}
Data = {this.state.DB[key]}
updateDB={this.updateDB} />
)
}
</ul>
</div>
);
}
}
export default App;
import React, { Component } from 'react';
import Slider from 'react-rangeslider';
class AB_eval extends Component {
constructor(props, context){
super(props, context);
this.updateDB = this.updateDB.bind(this);
// Trying to make these variable instance variables
const {ID, Data} = this.props;
}
updateDB () {
this.props.updateDB(this.ID, this.Data) // updating the App's state
}
render() {
console.log(this.Data);
let {A, B, AB} = this.Data;
return (
<div>
<h1>AB_eval: {this.ID}</h1>
<h2>A</h2>
<p>A: {A} B: {B} AB:{AB}</p>
<Slider min={1} max={4} step={1}
value={A}
onChange={ (value)=> {
this.A = value;
this.AB = this.A * this.B;
this.updateDB();
}
}
/>
<h2>B</h2>
<p>A: {A} B: {B} AB:{AB}</p>
<Slider min={1} max={4} step={1}
value={B}
onChange={ (value)=> {
this.B = value;
this.AB = this.A * this.B;
this.updateDB();
}
}
/>
</div>
)
}
}
AB_eval.propTypes = {
ID: React.PropTypes.string.isRequired,
Data: React.PropTypes.object.isRequired,
updateDB: React.PropTypes.func.isRequired
};
export default AB_eval;
(不确定我是否在正确的位置使用const
和let
)
在@Pineda和一些尝试的帮助下,我发现以下解决方案按照我的意愿工作:
SCR / App.js
import React, { Component } from 'react';
import './App.css';
import ABEval from './components/ABEval';
import dummyData from './dummy-data';
class App extends Component {
constructor() {
super();
this.updateDB = this.updateDB.bind(this);
// getInitialState
this.state = {
DB: dummyData
};
}
updateDB(key, bar) {
const DB = {...this.state.DB}
DB[key] = bar;
this.setState({ DB });
}
render() {
return (
<div className="App">
<ul className="list-of-ABs">
{ Object
.keys(this.state.DB)
.map(key =>
<ABEval
key={key}
ID={key}
Data={this.state.DB[key]}
updateDB={this.updateDB} />
)
}
</ul>
</div>
);
}
}
export default App;
SCR /伪data.js
module.exports = {
one: {A: 1,
B: 2,
AB: 2
},
two: { A: 3,
B: 4,
AB: 12
}
};
SCR /组件/ ABEval.js
import React, { Component } from 'react';
import XSlider from './XSlider';
class AB_eval extends Component {
constructor(props, context){
super(props, context);
console.log(`${this.props.ID}: Constructed`);
}
componentDidMount(){
console.log(`${this.props.ID}: Mounted`);
}
render() {
console.log(`${this.props.ID}: rendered`)
const { Data, ID } = this.props;
const { A, B, AB } = Data;
return (
<div>
<h1>ABEval: {ID}</h1>
<p>A: {A} B: {B} AB:{AB}</p>
<XSlider
title={'A'}
value={A}
valueHandler={
(val)=> this.props.updateDB(ID, {A: val, B: B, AB: val*B} )}
/>
<XSlider
title={'B'}
value={B}
valueHandler={
(val)=> this.props.updateDB(ID, {B: val, A: A, AB: val*A} )}
/>
</div>
)
}
}
AB_eval.propTypes = {
ID: React.PropTypes.string.isRequired,
Data: React.PropTypes.object.isRequired,
updateDB: React.PropTypes.func.isRequired
};
export default AB_eval;
SCR /组件/ XSlider.js
import React from 'react';
import Slider from 'react-rangeslider';
export default ({title, value, valueHandler}) => {
return (
<div>
<h2>{title}</h2>
<Slider min={1} max={4} step={1} value={value} onChange={valueHandler} />
</div>
);
}
答案 0 :(得分:1)
根据您提供的信息,很难做出许多重新分解建议,但数据流看起来还不错。
最新AB_eval.js中的问题:
const {ID, Data} = this.props; // block scoped, DOES NOT create class members
// referencable by this.ID or this.DATA
// outside the scope of its containing block
const
是块作用域,所以你的内部道具的解构 构造函数只会在其中创建一个可用的ID和Data值 构造函数块。这打破了后来
this.ID
和this.Data
的引用(在updateDB()
方法)。引用this.A
,this.AB
,this.B
和this.updateDB
方法中的render()
也将被破坏。修理 这个,我建议在你的块范围内解构道具 render和onChange handler(s)。
this.AB = this.A * this.B; // state should be treated as immutable
// and since props are propogated by changes in state
// mutating them is ill-advised
尝试直接在this.props.Data中设置值 onChange方法有效地改变应该被视为什么的方法 不可变的。
使用ES6 / ES7可以通过几种方法确保无突变 表示法,一个使用Object.assign,另一个使用Spread syntax notation。
<强>解决方案强>
AB_eval.js:
import React, { Component } from 'react';
import Slider from 'react-rangeslider';
class AB_eval extends Component {
constructor(props, context){
super(props, context);
this.onChangeA = this.onChangeA.bind(this);
this.onChangeB = this.onChangeB.bind(this);
}
onChangeA (value) {
const {ID, Data, updateDB} = this.props;
updateDB(ID, {
...Data,
A: value,
AB: value * Data.B
});
}
onChangeB (value) {
const {ID, Data, updateDB} = this.props;
updateDB(ID, {
...Data,
B: value,
AB: value * Data.B
});
}
render() {
const {A, B, AB} = this.props.Data;
return (
<div>
<h1>AB_eval: {this.props.ID}</h1>
<h2>A</h2>
<p>A: {A} B: {B} AB:{AB}</p>
<Slider min={1} max={4} step={1}
value={A}
onChange={this.onChangeA}
/>
<h2>B</h2>
<p>A: {A} B: {B} AB:{AB}</p>
<Slider min={1} max={4} step={1}
value={B}
onChange={this.onChangeB}
}
/>
</div>
)
}
}
AB_eval.propTypes = {
ID: React.PropTypes.string.isRequired,
Data: React.PropTypes.object.isRequired,
updateDB: React.PropTypes.func.isRequired
};
export default AB_eval;
onChangeA
和onChangeB
)替换,以处理A和B的滑块情况。this
。 关于重构的更新:
您可以将Slider代码提取到一个功能组件中(我已经添加了一个文件夹结构作为建议):
./组件/ AB_eval_slider.js
import React from 'react'; export default ({key, db, handler}) => { return ( <div> <h2>{key}</h2> <p>A: {db.A} B: {db.B} AB:{db.AB}</p> <Slider min={1} max={4} step={1} value={key} onChange={handler} /> </div> ); }
因此,您还必须编辑我建议的 AB_eval.js 以包含:
import AB_eval_Slider from './components/AB_eval_slider';
,渲染方法现在是:
render() {
return (
const { Data } = this.props;
<div>
<h1>AB_eval: {this.ID}</h1>
<AB_eval_Slider key={'A'} db={Data}, handler={this.onChangeA} />
<AB_eval_Slider key={'B'} db={Data}, handler={this.onChangeB} />
</div>
);
}
答案 1 :(得分:1)
老实说,我无法理解你的代码是什么,但是从代码示例和你的问题是 我能想到的是:
dummyData.js
export default {
one: {A: 1,
B: 2,
AB: 2
},
two: { A: 3,
B: 4,
AB: 12
}
};
App.js
import React, { Component } from 'react';
import './App.css';
import dummyData from './dummyData';
import AB_eval from './components/AB_eval';
class App extends Component {
constructor() {
super();
// getInitialState
this.state = dummyData;
this.updateDB = (id, value) => this.setState({ id: value });
}
render() {
return (
<div className="App">
<ul className="list-of-ABs">
{ Object
.keys(this.state)
.map(key =>
<AB_eval
key = {key}
ID = {key}
Data = {this.state[key]}
updateDB={this.updateDB} />
)
}
</ul>
</div>
);
}
}
export default App;
如果您只在应用的状态下拥有key: value
存储空间,那么您不需要DB
密钥,只需将状态设置为key: value
存储空间即可在this.state = dummyData
之上,我认为状态树不那么深入,更难以思考和操作它。
您可以在此处使用箭头功能来“绑定”this
,例如此处this.updateDB = (id, value) => this.setState({ id: value });
。这样您就不需要先定义一个函数,然后将this
“绑定”到它中。代码越来越少,代码通常更少,我猜想。
AB_eval.js
import React, { Component } from 'react';
import Slider from 'react-rangeslider';
class AB_eval extends Component {
constructor(props, context){
super(props, context);
this.updateDB = (type, value) => {
const { ID, DATA } = this.props
switch(type) {
case "A":
this.props.updateDB(
ID,
{ ...DATA, A: value, AB: (value * DATA.B) }
);
break;
case "B":
this.props.updateDB(
ID,
{ ...DATA, B: value, AB: (DATA.A * value) }
);
break;
default:
this.props.updateDB(
ID, DATA
);
break;
}
};
}
componentDidMount () {
this.updateDB();
}
render() {
const {A, B, AB} = this.props.DATA;
return (
<div>
<h1>AB_eval: {AB}</h1>
<h2>A</h2>
<p>A: {A} B: {B} AB:{AB}</p>
<Slider min={1} max={4} step={1}
value={A}
onChange={ (value)=> this.updateDB("A", value) }
}
/>
<h2>B</h2>
<p>A: {A} B: {B} AB:{AB}</p>
<Slider min={1} max={4} step={1}
value={B}
onChange={ (value)=> this.updateDB("B", value) }
/>
</div>
)
}
}
AB_eval.propTypes = {
ID: React.PropTypes.string.isRequired,
DATA: React.PropTypes.object.isRequired,
updateDB: React.PropTypes.func.isRequired
};
export default AB_eval;
首先想到我能想到你的AB_eval
组件,它不需要state
它自己的组件。因为所有状态的内容都可以通过props
获得。正如在React
documentation上所说,你应该:
找出应用程序所需状态的绝对最小表示形式,并按需计算所需的其他所有内容。
将状态放在一个位置,通常位于组件层次结构顶部的组件中,这使得理解您的应用程序变得更加容易。
我认为React's
文档网站上的这个awsome material可以帮助您在React
创建应用时获得很多帮助。
以下是关于const
和let
here on youtube的精彩教程。但简而言之,只要您不需要更改变量,就可以使用const
。将其视为constant
变量。最好使用constant
将值定义为const
,这样您就不会更改它。仅在以后需要更改变量时才使用let
。
答案 2 :(得分:0)
在您的示例中,没有必要在updateDB
组件中执行App
。您可以在updateDB
中执行AB_eval
操作。您可以在A
构造函数中初始化B
,AB_eval
,而不是从App
组件获取,因为它们是常量。