React组件中的Prop被突变

时间:2016-10-19 20:41:10

标签: javascript reactjs

我有一个奇怪的场景,其中React组件中的prop正在变异。它是一个数组,所以它在技术上不是一个变异(在JavaScript领域),但仍然没有办法应该修改。

我做了一个准确的例子来复制这个问题。 http://codepen.io/HoraceShmorace/pen/LRXWWb?editors=0011

这个组件:

  1. 接受包含初始“组”数据的道具,
  2. 允许您过滤该组数据(通过文本框),
  3. 将状态属性设置为已过滤的组数据
  4. 然后并排显示初始道具数据和过滤后的状态数据。
  5. 组数据是一个组列表,每个组都有一个名称和一个子对象数组。这些子对象将代表人{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;
    }
    

1 个答案:

答案 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(_:)