0
私は、React成分中のプロットが突然変異しているという奇妙なシナリオを持っています。配列なので、技術的に突然変異ではありませんが(JavaScriptの土地では)、まだ変更する必要はありません。突然変異を起こしている反応成分中のプロブレム
問題を再現するために、ベアボーンの例を作成しました。 http://codepen.io/HoraceShmorace/pen/LRXWWb?editors=0011。
この成分:
- を使用して、(テキストボックスを介して)、グループデータ、
- を濾過する状態プロパティを設定することをフィルタリングすることを可能にする
- 、初期の「グループ」データを含む支柱を受け付けグループデータ、
- を入力し、最初の小道具データとフィルタリングされた状態データを並べて表示します。
グループデータは、名前と子オブジェクトの配列を持つグループのリストです。これらの子オブジェクトは、人物{name:[value]}
、または複数のグループを表し、階層を形成します。
グループデータのフィルタリングが正しく行われます。しかし、何らかの理由で州と小道の両方が更新されています。ここで
はJSです:
/**
* Define the component.
*/
class TestComponent extends React.Component {
constructor(props) {
super(props)
const {initialGroups} = this.props
//Initialize filtered groups with the intial groups
this.state = {
filteredGroups: initialGroups
}
}
/**
* Simply outputs the props and the state to the screen,
* as well as an input field that filters the group data.
*/
render() {
return (
<div>
<input type="text" placeholder="Filter by name" onChange={onChange.bind(this)} />
<section id="output">
<pre>
<h1>props:</h1>
{JSON.stringify(this.props,null,2)}
</pre>
<pre>
<h1>state:</h1>
{JSON.stringify(this.state,null,2)}
</pre>
</section>
</div>
)
}
}
TestComponent.propTypes = {
initialGroups: React.PropTypes.array.isRequired
}
/**
* Define event handler for text input change,
* which filters group data recursively,
* the result of which gets saved in state.
*/
function onChange(e) {
//Get input value
const filterInputValue = e.target.value
//Get initial group data to filter. Note how this is copying the array, non-mutatingly, just in case.
const initialGroups = [...this.props.initialGroups]
//Filter the group data (function defined below).
const filteredGroups = filterGroupsByPerson(initialGroups)
//Update the state
this.setState({filteredGroups})
//Recursive filtering function
function filterGroupsByPerson(arr) {
return arr.filter(item=>{
const hasChildren = item.children instanceof Array && item.children.length > 0
//Having children implies this is a group. Don't test the name, just try to filter the children.
if(hasChildren) {
//Filter children array recursively
item.children = filterGroupsByPerson(item.children)
return item.children.length > 0
}
//This is a person, not a group. Filter on the name.
const filterRegex = new RegExp(filterInputValue, 'i')
const filterResults = filterRegex.test(item.name)
return filterResults
})
}
}
/**
* Mock up the initial group data
*/
const InitialGroups = [
{
"name": "Engineering",
"children": [
{"name": "Gates"},
{"name": "Allen"},
{"name": "Jobs"},
{"name": "Wozniak"},
{
"name": "Consultants",
"children": [
{"name": "Jess"},
{"name": "Cece"},
{"name": "Winston"},
{"name": "Schmidt"}
]
},
]
}
]
/**
* Implement component, passing initial group data as a prop.
*/
ReactDOM.render(<TestComponent initialGroups={InitialGroups}/>, document.getElementById('test-component'))
そしてHTMLの少し:あなたが行うことができます
#output {
display:flex;
}
#output pre {
background-color: #eeeecc;
margin-right: 20px;
}
'[... this.props.initialGroups]'は**浅い**コピーのみを実行します。配列内のオブジェクトはコピーされないので、 'item.children = filterGroupsByPerson(item.children)'があなたが見るエフェクトの理由です。言い換えれば、小道具と州は両方とも、同じオブジェクトを参照しているので更新されているように見える。深いコピーをしたいようです。 –
なぜですか? ...... –
新しい配列内の項目は、古い配列内の同じ項目への参照であると言っていますか? – Horace