我在开发的一个非常基本的颜色和谐选择器中遇到了几个问题。我仍然是 React 和 JSX 的初学者。我最初把它放在 GitHub 上,所以完整的文件在那里,但我把它移到了 Codepen。
Here is the Codepen
我做了很多评论,如果他们有点多,我很抱歉,但希望他们有所帮助。我的问题直到第 41 行,DataStore 类的 displayHarmonies() 方法才开始。传递给它的值来自我的 App(父)组件:
displayHarmonies(color, harmony) {
//color and harmony pass in dynamically just fine...this.data will not return anything, not even "undefined"
console.log(color + " is the color and " + harmony + " is the harmony...and dataStore.displayHarmonies says: " + this.data);
this.registeredWatchers.map((watcher) => {
let result = "not green"; //result and resultHex will be determined with an underscore statement that will associate the color & harmony choice (primary + foreign key concept) and will return correct harmony color(s)
let resultHex = "#HEX";
appState.harmonyColor = result;
appState.harmonyHex = resultHex;
//call to app component's onDataChange() method, where new states will be set using the the appState data we just set in lines 49 and 50
watcher.onDataChange();
})
}
从我的第一条评论中可以看出,唯一没有登录到控制台的部分是 this.data,它是在 DataStore 的构造函数中设置的:
constructor(data) {
//store that data in the object
//data is not being received from object instance of dataStore on line 187
this.data = data;
在第 187 行,我创建了一个 DataStore 的实例并将一个名为
data
的变量传递给它。 .在使用之前,这个变量被初始化,然后通过 Fetch API 分配给解析的 JSON 数据:let data = [];
//use polyfill for older browsers to do Ajax request
fetch("data/data.json").then((response) => {
//if we actually got something
if (response.ok) {
//then return the text we loaded
return response.text();
}
}).then((textResponse) => {
data = JSON.parse(textResponse);
});
如果我在第二次获取
.then()
中调出数据方法,JSON 回来就好了。一旦我尝试使用 data
变量在应用程序的任何其他地方,它什么都不返回,如 displayHarmonies()
所示方法console.log()
.所以这是我的第一个问题,但在我想解决这个问题之前,我想解决我遇到的另一个问题。在
appState
之后对象(在 DataStore 之前初始化,在 fetch 语句下)值设置为 result
变量,displayHarmonies()
运行 watcher.onDataChange()
(在 App 组件/父级中)其中 harmonyColor
和 harmonyHex
状态被分配给新的 appState
值(value)观:onDataChange() {
console.log("onDataChange() in App called");
this.setState({
harmonyColor: appState.harmonyColor,
harmonyHex: appState.harmonyHex
})
}
如果我将这些状态记录到控制台,它们就是正确的值,所以这不是问题。然后我将我的状态传递给
Display
要用作属性的子组件:<Display colorChoice={this.state.currentColor} harmonyChoice={this.state.currentHarmony} harmonyColor={this.state.harmonyColor} harmonyHex={this.state.harmonyHex} />
然后我设置
Display
构造函数中的组件状态,将它们分配给随着应用程序的每次新呈现发送给它的 Prop 。然后我使用 Display
将数据显示到 DOM 上。组件的渲染方法。奇怪的是,应用程序会很好地显示初始状态(颜色:红色、和谐:直接、和谐颜色:绿色等),但是一旦进行更改,DOM 上的数据就不会更新。初始数据以相同的方式加载:通过将父级的状态传递给子级的属性。我有几个console.log()
s 似乎证明了为什么这应该有效,但是,它没有。那么我做错了什么?谢谢,希望这不是一个问题!
最佳答案
首先是您当前的代码,在帖子的末尾,我添加了一个替代解决方案,所以如果这是 tl;dr;只需跳到最后的片段:)
首先要说的是 data
变量,您希望将其传递给您的 DataStore
,nl (我省略了一些部分,因为它们与讨论无关)
let data = [];
fetch("data/data.json").then(( response ) => {
data = JSON.parse( response.text() );
});
//... later down the code
var store = new DataStore(data);
在这里,您在 fetch 调用的
data
promise 链中重新分配 then
变量。尽管分配似乎可以工作,但现在位于 store.data
上的数据将是一个空数组,全局变量 data
现在将包含已解析的 response.text()
。您可能应该只插入刚刚解析的数据(但在我的示例中,我什至没有包含 DataStore
,所以这仅供将来引用)在您的 CodePen 中,您似乎为
Display
组件混合了 Prop 和状态。这本质上是一个无操作,除非你真的知道你在做什么,否则你不应该混合它们。另请注意,通过在 this.setState
生命周期方法中调用 componentWillReceiveProps
,应用程序将自动重新渲染超出需要的部分。我指的是这段代码:componentWillReceiveProps(nextProps) {
this.setState({
color: nextProps.colorChoice,
harmony: nextProps.harmonyChoice,
harmonyColor: nextProps.harmonyColor,
harmonyHex: nextProps.harmonyHex
});
}
但是你会像这样渲染:
render() {
return (
<div>
{/* these aren't changing even though states are being set */}
<p><b>Color:</b> {this.state.color}</p>
<p><b>Harmony:</b> {this.state.harmony}</p>
<p><b>Harmony Color(s):</b> {this.state.harmonyColor} ({this.state.harmonyHex})</p>
</div>
)
}
在这里,您应该删除
componentWillReceiveProps
方法,并从 this.props
渲染值,因为您从 App
传递这些值。替代解决方案
正如评论中提到的,您的代码目前在父组件和子组件之间传递状态的工作比它应该做的要多得多。
您应该记住的一件事是,当组件状态发生更改时,react 将自动重新渲染组件。当它发现虚拟 DOM 与真实 DOM 存在差异时,它会自动替换这些组件。
从这个意义上说,你的
DataStore
是没有必要的。根据您希望如何管理状态,组件将对这些更改使用react。由于您的应用程序使用组件状态(这对于小型应用程序来说很好,一旦您想迁移到更大的应用程序,您可能会想要迁移到 Redux 或 MobX 之类的东西),您唯一需要做的就是让确保设置正确的组件状态以触发渲染。
例如,我以更简洁的方式重新编写了您的代码:
const Choice = ({ header, values, onChange, activeValue }) => {
return <ul>
<li><h1>{ header }</h1></li>
{ values.map( (value, key) => <li
key={key+value}
className={classNames( { active: value === activeValue, item: true } )}
onClick={() => onChange( value )}>{ value }</li> ) }
</ul>
};
const colors = ['red', 'green', 'black', 'blue', 'yellow'];
const harmonies = ['direct', 'split', 'analogous'];
class App extends React.Component {
constructor(...args) {
super(...args);
this.state = {
activeColor: undefined,
activeHarmony: undefined
};
}
onColorChanged( color ) {
this.setState({ activeColor: color });
}
onHarmonyChanged( harmony ) {
this.setState({ activeHarmony: harmony });
}
render() {
let { activeColor, activeHarmony } = this.state;
return <div>
<Choice
header="Choose color"
values={colors}
activeValue={activeColor}
onChange={(...args) => this.onColorChanged(...args)} />
<Choice
header="Choose harmony"
values={harmonies}
activeValue={activeHarmony}
onChange={(...args) => this.onHarmonyChanged(...args)} />
</div>;
}
}
ReactDOM.render( <App />, document.querySelector('#container'));
h1 { margin: 0; padding: 0; }
ul {
list-style-type: none;
}
.item {
cursor: pointer;
padding: 5px;
}
.active { background-color: lightgreen; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.2/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.2/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.6.0/prop-types.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/classnames/2.2.5/index.js"></script>
<div id="container"></div>
现在,此示例代码中有一些内容可能需要解释一下。一方面,此代码有 2 种组件类型,1 个称为
Choice
的无状态表示组件,以及一个称为 App
的容器组件,它将其状态委托(delegate)给它的子级。关于容器和展示组件的更多信息可以在 Dan Abramov(redux 创建者)的 blog 上找到
上述概念的本质就是这样,
App
组件负责状态,并与它的 child 共享它。因此,所有状态更改都需要在 App
组件上进行。正如您在渲染中看到的,App
只是简单地传递其状态:render() {
let { activeColor, activeHarmony } = this.state;
return <div>
<Choice
header="Choose color"
values={colors}
activeValue={activeColor}
onChange={(...args) => this.onColorChanged(...args)} />
<Choice
header="Choose harmony"
values={harmonies}
activeValue={activeHarmony}
onChange={(...args) => this.onHarmonyChanged(...args)} />
</div>;
}
App
将更改处理程序传递到Choice
组件,可以在应发生选择时调用,这会转发到App
,状态更改和应用程序重新渲染,允许Choice
组件更新它的元素。const Choice = ({ header, values, onChange, activeValue })
根据传入的 props,
Choice
组件可以决定渲染时哪个是事件项。如您所见, Prop 已被破坏。 header
、 values
、 onChange
和 activeValue
都是组件的 props
上的属性,但是为了节省时间,我们可以将这些值分配给一个变量并在渲染中使用它们。
关于javascript - react .js : Parent state values not passing into child properties + Fetch API data cannot be accessed,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47726324/