我有两个React Native'场景',其中一个在另一个场景中启动谜题。在launch.js中,我从单独的数据文件中检索数据,如下所示:
import fileData from './data.js';
//var fileData = require('./data.js'); <= I've had it this way, too; data.js is a module.exports of an array-type object
我将数据传递给game.js,如下所示:
onSelect(passed) {
var inFileData = fileData; //*** this is just a debugging abstraction so I can see what the values are
this.props.navigator.replace({
id: 'game board',
passProps: {
title: passed,
theData: fileData,
},
});
}
数据是在game.js中获得的,
constructor(props) {
super(props);
this.state = {
id: 'game board',
title: this.props.title,
theData: this.props.theData, //<= here
};
我的问题是,当我在游戏中做“填充”时,例如用
更改单词的值 var data = this.props.theData;
data[index].word = "test";
this.setState({theData: data});
当我回到launch.js(然后回到game.js)时,这些更改仍然存在,甚至在变量inFileData(上面的***注释)中的值反映了在游戏而不是data.js文件中的内容。另外,在game.js中,我无法保存导入数据的任何副本(即使使用kludgy for循环来尝试复制对象)来重置值,所有这些都让我相信我错过了一些React状态模型的关键基础。任何人都可以对我出错的地方有所了解吗?
答案 0 :(得分:0)
我终于使用deepClone调用this cloning function解决了这个问题(花了2天之后!)。这个函数在this excellent article中描述,我在古老而又多得多的投票StackOverflow问题How do I correctly clone a JavaScript object?
中看到了这个问题。我将整个“owl”函数作为deepCopy.js包含在我的React Native项目中
var deepCopy = require('./deepCopy.js');
追加
后module.exports = owl;
到deepCopy.js文件,然后将其与
一起使用var copy = owl.deepCopy(fileData);
和
this.props.navigator.replace({
id: 'game board',
passProps: {
title: passed,
theData: copy,
},
请注意,因为这不是一个Web环境,所以我必须注释掉owl函数的“HTML DOM Node”部分,因为它引用了React Native不喜欢的“document”。
我想这里的问题是正在克隆的数组的深度,更深层次的引用仍然保留。似乎必须存在一个更原生的解决方案,但至少这个有效...我会等到有人在进一步输入之前将其标记为已回答。
编辑:我将包含代码,以防它被删除:
/* This file is part of OWL JavaScript Utilities.
OWL JavaScript Utilities is free software: you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
OWL JavaScript Utilities is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with OWL JavaScript Utilities. If not, see
<http://www.gnu.org/licenses/>.
*/
owl = (function() {
// clone objects, skip other types.
function clone(target) {
if ( typeof target == 'object' ) {
Clone.prototype = target;
return new Clone();
} else {
return target;
}
}
// Shallow Copy
function copy(target) {
if (typeof target !== 'object' ) {
return target; // non-object have value sematics, so target is already a copy.
} else {
var value = target.valueOf();
if (target != value) {
// the object is a standard object wrapper for a native type, say String.
// we can make a copy by instantiating a new object around the value.
return new target.constructor(value);
} else {
// ok, we have a normal object. If possible, we'll clone the original's prototype
// (not the original) to get an empty object with the same prototype chain as
// the original. If just copy the instance properties. Otherwise, we have to
// copy the whole thing, property-by-property.
if ( target instanceof target.constructor && target.constructor !== Object ) {
var c = clone(target.constructor.prototype);
// give the copy all the instance properties of target. It has the same
// prototype as target, so inherited properties are already there.
for ( var property in target) {
if (target.hasOwnProperty(property)) {
c[property] = target[property];
}
}
} else {
var c = {};
for ( var property in target ) c[property] = target[property];
}
return c;
}
}
}
// Deep Copy
var deepCopiers = [];
function DeepCopier(config) {
for ( var key in config ) this[key] = config[key];
}
DeepCopier.prototype = {
constructor: DeepCopier,
// determines if this DeepCopier can handle the given object.
canCopy: function(source) { return false; },
// starts the deep copying process by creating the copy object. You
// can initialize any properties you want, but you can't call recursively
// into the DeeopCopyAlgorithm.
create: function(source) { },
// Completes the deep copy of the source object by populating any properties
// that need to be recursively deep copied. You can do this by using the
// provided deepCopyAlgorithm instance's deepCopy() method. This will handle
// cyclic references for objects already deepCopied, including the source object
// itself. The "result" passed in is the object returned from create().
populate: function(deepCopyAlgorithm, source, result) {}
};
function DeepCopyAlgorithm() {
// copiedObjects keeps track of objects already copied by this
// deepCopy operation, so we can correctly handle cyclic references.
this.copiedObjects = [];
thisPass = this;
this.recursiveDeepCopy = function(source) {
return thisPass.deepCopy(source);
}
this.depth = 0;
}
DeepCopyAlgorithm.prototype = {
constructor: DeepCopyAlgorithm,
maxDepth: 256,
// add an object to the cache. No attempt is made to filter duplicates;
// we always check getCachedResult() before calling it.
cacheResult: function(source, result) {
this.copiedObjects.push([source, result]);
},
// Returns the cached copy of a given object, or undefined if it's an
// object we haven't seen before.
getCachedResult: function(source) {
var copiedObjects = this.copiedObjects;
var length = copiedObjects.length;
for ( var i=0; i<length; i++ ) {
if ( copiedObjects[i][0] === source ) {
return copiedObjects[i][1];
}
}
return undefined;
},
// deepCopy handles the simple cases itself: non-objects and object's we've seen before.
// For complex cases, it first identifies an appropriate DeepCopier, then calls
// applyDeepCopier() to delegate the details of copying the object to that DeepCopier.
deepCopy: function(source) {
// null is a special case: it's the only value of type 'object' without properties.
if ( source === null ) return null;
// All non-objects use value semantics and don't need explict copying.
if ( typeof source !== 'object' ) return source;
var cachedResult = this.getCachedResult(source);
// we've already seen this object during this deep copy operation
// so can immediately return the result. This preserves the cyclic
// reference structure and protects us from infinite recursion.
if ( cachedResult ) return cachedResult;
// objects may need special handling depending on their class. There is
// a class of handlers call "DeepCopiers" that know how to copy certain
// objects. There is also a final, generic deep copier that can handle any object.
for ( var i=0; i<deepCopiers.length; i++ ) {
var deepCopier = deepCopiers[i];
if ( deepCopier.canCopy(source) ) {
return this.applyDeepCopier(deepCopier, source);
}
}
// the generic copier can handle anything, so we should never reach this line.
throw new Error("no DeepCopier is able to copy " + source);
},
// once we've identified which DeepCopier to use, we need to call it in a very
// particular order: create, cache, populate. This is the key to detecting cycles.
// We also keep track of recursion depth when calling the potentially recursive
// populate(): this is a fail-fast to prevent an infinite loop from consuming all
// available memory and crashing or slowing down the browser.
applyDeepCopier: function(deepCopier, source) {
// Start by creating a stub object that represents the copy.
var result = deepCopier.create(source);
// we now know the deep copy of source should always be result, so if we encounter
// source again during this deep copy we can immediately use result instead of
// descending into it recursively.
this.cacheResult(source, result);
// only DeepCopier::populate() can recursively deep copy. So, to keep track
// of recursion depth, we increment this shared counter before calling it,
// and decrement it afterwards.
this.depth++;
if ( this.depth > this.maxDepth ) {
throw new Error("Exceeded max recursion depth in deep copy.");
}
// It's now safe to let the deepCopier recursively deep copy its properties.
deepCopier.populate(this.recursiveDeepCopy, source, result);
this.depth--;
return result;
}
};
// entry point for deep copy.
// source is the object to be deep copied.
// maxDepth is an optional recursion limit. Defaults to 256.
function deepCopy(source, maxDepth) {
var deepCopyAlgorithm = new DeepCopyAlgorithm();
if ( maxDepth ) deepCopyAlgorithm.maxDepth = maxDepth;
return deepCopyAlgorithm.deepCopy(source);
}
// publicly expose the DeepCopier class.
deepCopy.DeepCopier = DeepCopier;
// publicly expose the list of deepCopiers.
deepCopy.deepCopiers = deepCopiers;
// make deepCopy() extensible by allowing others to
// register their own custom DeepCopiers.
deepCopy.register = function(deepCopier) {
if ( !(deepCopier instanceof DeepCopier) ) {
deepCopier = new DeepCopier(deepCopier);
}
deepCopiers.unshift(deepCopier);
}
// Generic Object copier
// the ultimate fallback DeepCopier, which tries to handle the generic case. This
// should work for base Objects and many user-defined classes.
deepCopy.register({
canCopy: function(source) { return true; },
create: function(source) {
if ( source instanceof source.constructor ) {
return clone(source.constructor.prototype);
} else {
return {};
}
},
populate: function(deepCopy, source, result) {
for ( var key in source ) {
if ( source.hasOwnProperty(key) ) {
result[key] = deepCopy(source[key]);
}
}
return result;
}
});
// Array copier
deepCopy.register({
canCopy: function(source) {
return ( source instanceof Array );
},
create: function(source) {
return new source.constructor();
},
populate: function(deepCopy, source, result) {
for ( var i=0; i<source.length; i++) {
result.push( deepCopy(source[i]) );
}
return result;
}
});
// Date copier
deepCopy.register({
canCopy: function(source) {
return ( source instanceof Date );
},
create: function(source) {
return new Date(source);
}
});
// HTML DOM Node
// utility function to detect Nodes. In particular, we're looking
// for the cloneNode method. The global document is also defined to
// be a Node, but is a special case in many ways.
function isNode(source) {
if ( window.Node ) {
return source instanceof Node;
} else {
// the document is a special Node and doesn't have many of
// the common properties so we use an identity check instead.
if ( source === document ) return true;
return (
typeof source.nodeType === 'number' &&
source.attributes &&
source.childNodes &&
source.cloneNode
);
}
}
// Node copier
deepCopy.register({
canCopy: function(source) { return isNode(source); },
create: function(source) {
// there can only be one (document).
if ( source === document ) return document;
// start with a shallow copy. We'll handle the deep copy of
// its children ourselves.
return source.cloneNode(false);
},
populate: function(deepCopy, source, result) {
// we're not copying the global document, so don't have to populate it either.
if ( source === document ) return document;
// if this Node has children, deep copy them one-by-one.
if ( source.childNodes && source.childNodes.length ) {
for ( var i=0; i<source.childNodes.length; i++ ) {
var childCopy = deepCopy(source.childNodes[i]);
result.appendChild(childCopy);
}
}
}
});
return {
DeepCopyAlgorithm: DeepCopyAlgorithm,
copy: copy,
clone: clone,
deepCopy: deepCopy
};
})();
module.exports = owl;