我有一个奇怪的场景,其中React组件中的prop正在变异。它是一个数组,所以它在技术上不是一个变异(在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:
<div id="test-component"></div>
...和CSS:
#output {
display:flex;
}
#output pre {
background-color: #eeeecc;
margin-right: 20px;
}
答案 0 :(得分:0)
你可以这样做:
const filterInputValue = e.target.value
const intialGroupClone = JSON.parse(JSON.stringify(this.props.initialGroups))
const filteredGroups = filterGroupsByPerson(intialGroupClone)
//Update the state
this.setState({filteredGroups})
在这里工作笔flatMap(_:)