React Js使用onChange将数组内的值更新到子组件

Posted

技术标签:

【中文标题】React Js使用onChange将数组内的值更新到子组件【英文标题】:React Js Updating a value inside a array with onChange to a child component 【发布时间】:2019-10-17 19:32:10 【问题描述】:

我在渲染函数中映射了一个包含 opening_hours 的列表。我将它们映射到子组件。当子组件状态发生更改时,我想更改父状态中每个对象的值。唯一的问题是我的值在子组件和父状态中都没有改变。我已经将onChange方法传递给每个子组件,但问题在于我的onChange函数在父状态下。

我尝试将 onChange 传递给我的子组件并使用 [e.target.name] 更新状态:e.target.value。但这没有用。所以我尝试复制arrayList并根据映射arrayList的索引更新状态。那也没用。

    handleOnChange =  (index) => 
        let newData = [...this.state.opening_hours];
        this.setState(
            newData.map((barbershop, j) => 
                if (j === index) 
                    return barbershop;
                    console.log(barbershop)
                
            return 
                newData,
            ;
        ));
        console.log(newData)
    ;

    render() 
        return (
            <>
                <div className="container mb-2">
                    <h4>Opening hours </h4>
                    <Form>
                        this.state.opening_hours.map((barbershop, index) => (
                            <Day
                                key=barbershop.id
                                day=barbershop.day
                                open_time=barbershop.open_time
                                close_time=barbershop.close_time
                                index = index
                                onChange=() => this.handleOnChange(index)/>
                        ))
                    </Form>


                    <Button onClick=this.handleSubmit variant="primary" type="submit">
                        Update opening hours
                    </Button>
                </div>
            </>
        );
    

我的子组件是这样的

class Day extends Component 

    constructor(props) 
        super(props);
        this.state = 
            day: this.props.day,
            open_time: this.props.open_time,
            close_time: this.props.close_time,
        ;
        console.log(this.state)
    

    handleChange = () => 
        this.props.onChange(this.props.index)
    

    render() 
        return (
                <Form.Group as=Row>
                <Form.Label column sm="3">
                    ENUM[this.state.day]
                </Form.Label>
                <Col sm="3">
                    <Form.Control
                        name="open_time"
                        value=this.state.open_time
                        onChange=this.handleChange
                        type="time"
                        min="08:00"
                        max="24:00"/>
                </Col>
                <Col sm="3">
                    <Form.Control
                        name="close_time"
                        value=this.state.close_time
                        onChange=this.handleChange
                        type="time"
                        min="08:00"
                        max="24:00"/>
                </Col>
            </Form.Group>
        );
    


编辑:

【问题讨论】:

【参考方案1】:

您正在传递一个调用this.handleChange(index) 的函数,但您确实应该将该方法作为道具传递给您的&lt;Day /&gt; 组件并在那里调用它。你已经传入了index(虽然我会改用barbershop.id

所以在你的父组件中,我会这样做:

<Day 
  key=barbershop.id
  day=barbershop.day
  open_time=barbershop.open_time
  close_time=barbershop.close_time
  index = barbershop.id
  handleChange=this.handleOnChange
/>

然后在父组件的this.handleChange 方法中,如果您只是想为特定理发店获取this.state.opening_hours,我会这样做:

handleChange = (id) => 
  this.setState(() => (
    opening_hours: this.state.opening_hours.filter((barbershop) =>  
      return barbershop.id === id;
    )
  ))

【讨论】:

当我尝试这个时,我的整个数组消失了。这怎么可能? 我只剩下一个问题了。每次我更改值时,它都会在我的数组中创建一个新对象,而不会更改数组中特定值的值。这是我当前的代码:我已经像这样使用了扩展运算符,但它现在说“列表中的每个孩子都应该有一个唯一的“键”道具。”我该如何解决?这就是我现在拥有代码的方式:handleOnChange = (id) => this.setState(previousState => ( opening_hours: [...previousState.opening_hours, this.state.opening_hours.filter((barbershop) => return barbershop.id === id; ) ])) 你可以这样做:this.setState(prevState =&gt; ( ...prevState, opening_hours: this.state.opening_hours.filter((barbershop) =&gt; return barbershop.id === id; ) )) @Jbonez87 我已经使用了你的新解决方案,但它仍然删除了整个数组。 @TonyStark 你想对这个数组做什么?您是否要过滤掉所有与该 ID 不匹配的理发店并返回该理发店?从您的原始代码来看,这就是您想要做的事情。能否分享一下父组件挂载时this.state.opening_hours 以什么值开头?【参考方案2】:

所以我做了一些调查,我认为问题在于您没有将数据返回给消费者。

这是我的想法,解决方案是:

import React,  Component, useState, useEffect  from "react";

class UI extends Component 
  handleOnChange = ( index, ...newHours ) => 
    // update array item
    const opening_hours = this.state.opening_hours.map((item, i) => 
      const newData = i === index ? newHours : ;

      return 
        ...item,
        ...newData
      ;
    );

    // update item in opening_hours => state
    this.setState( opening_hours );
  ;

  render() 
    return (
      <div className="container mb-2">
        <h4>Opening hours</h4>

        <Form>
          this.state.opening_hours.map(( id, ...barbershop , index) => (
            <Day
              key=id
              ...barbershop
              ... index 
              onChange=this.handleOnChange
            />
          ))
        </Form>

        <Button onClick=this.handleSubmit variant="primary" type="submit">
          Update opening hours
        </Button>
      </div>
    );
  


const Day = ( day, onChange, index, ...props ) => 
  const [open_time, setOpenTime] = useState(props.open_time);
  const [close_time, setCloseTime] = useState(props.close_time);

  useEffect(() => 
    onChange( index, open_time, close_time );
  , [open_time, close_time, onChange, index]);

  const sharedProps = 
    type: "time",
    min: "08:00",
    max: "24:00"
  ;

  return (
    <Form.Group as=Row>
      <Form.Label column sm="3">
        ENUM[day]
      </Form.Label>

      <Col sm="3">
        <Form.Control
          ...sharedProps
          name="open_time"
          value=open_time
          onChange=( target ) => setOpenTime(target.value)
        />
      </Col>

      <Col sm="3">
        <Form.Control
          ...sharedProps
          name="close_time"
          value=close_time
          onChange=( target ) => setCloseTime(target.value)
        />
      </Col>
    </Form.Group>
  );
;

【讨论】:

当我更改某一天的 open_time 和 close_time 时,它​​每天都会更改。有时它会改变另一天。这真的很随机​​,我用 console.log 试过了。这怎么可能? 你可以试试i === index 是的!它终于奏效了。你能解释一下它是如何工作的吗?以及为什么它与我的不同。我真的很想从我的错误中吸取教训,并感谢你帮助了我。 当然,代码背后的前提是您在组件更新时接收数据。我返回了数组项位置和所需数据的索引。映射非常简单,就是遍历数组中的每个项目,如果 map() 索引与处理程序中的索引匹配,那么它会获取数据并将其传播到现有数据上,从而在不更改数组顺序的情况下更新道具。 错误在于表达式。 Is 正在评估索引是否不是处理程序索引。因此,除了我们想要的项目之外的所有其他项目都在更新。这有助于澄清事情吗?

以上是关于React Js使用onChange将数组内的值更新到子组件的主要内容,如果未能解决你的问题,请参考以下文章

React JS - onChange触发两次

如何使用 onchange javascript 对循环内的值求和

动态修改JS对象的值及React setState

React 输入设置状态 onChange 设置多个状态属性

当用js动态的改变一个输入框中的值后,并不能触发它的onchange事件why?

React 的 Upload 文件表单编辑回显及 onChange 自定义回调的方式