【问题标题】:React Js Updating a value inside a array with onChange to a child componentReact Js使用onChange将数组内的值更新到子组件
【发布时间】: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>
        );
    }
}

编辑:

【问题讨论】:

    标签: javascript arrays reactjs components


    【解决方案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 正在评估索引是否不是处理程序索引。因此,除了我们想要的项目之外的所有其他项目都在更新。这有助于澄清事情吗?
    猜你喜欢
    • 1970-01-01
    • 2018-01-18
    • 2019-05-13
    • 2021-08-23
    • 2019-06-19
    • 1970-01-01
    • 1970-01-01
    • 2020-05-15
    • 2022-01-17
    相关资源
    最近更新 更多