简体   繁体   English

setState()不更新值

[英]setState() doesn't update value

I'm trying to update state of my component and it's not working. 我正在尝试更新组件的状态,但无法正常工作。 I have Main page container component => nested Navbar container component => nested NavItem UI component. 我有主页容器组件=>嵌套的Navbar容器组件=>嵌套的NavItem UI组件。 Also on Main page I have AddNavItem container component which should add item to Navbar. 同样在主页上,我有AddNavItem容器组件,应将项目添加到Navbar。 It looks like this: 看起来像这样:

Main
|
|--NavBar
|   |
|   |--NavItem
|
|--AddNavItem

This is my Main page code: 这是我的主页代码:

import React, { Component } from 'react';
import Navbar from '../nav/Navbar'
import AddNavItem from '../fields/AddNavItem'

class Main extends Component {
    state = {
        items: [
            {id: 1, name: 'Услуги', link: 'services'},
            {id: 2, name: 'Цены', link: 'prices'},
            {id: 3, name: 'Как это работает?', link: 'works'},
        ]
    }

    addNavItem = (item) => {
        this.setState((state) => {
            let newItems = [...state.items];
            newItems.unshift(item)
            console.log(newItems);
            return { 
               items: newItems
            }
        });
    }

    render() {
        return (
            <div>
                <Navbar items={ this.state.items }/>
                <AddNavItem addNavItem={ this.addNavItem }/>
            </div>
        );
    }
}

export default Main;

The problem is that I always get old array with 3 initial obj even after addNavItem is firing. 问题是即使在addNavItem触发后,我也总是会得到带有3个初始obj的旧数组。 <Navbar /> still gets array with 3 element. <Navbar />仍然获得具有3个元素的数组。 I have read about async setState and makes as describe in doc https://reactjs.org/docs/faq-state.html What have I doing wrong? 我已经阅读了有关异步setState的信息,并按照文档https://reactjs.org/docs/faq-state.html中的说明进行了操作。

UPD: I changed code (unshift) to return array, not a length of the array. UPD:我更改了代码(取消移位)以返回数组,而不是数组的长度。 Console log shows me that I get new array with 4 obj 控制台日志显示我得到了4个obj的新数组

UPD: My complete code for all components: UPD:我所有组件的完整代码:

Navbar 导航栏

import React, { Component } from 'react';
import NavItem from './NavItem';

class Navbar extends Component {
    state = {
        items: this.props.items,
    }

    render() {
        return (
            <div className="centered navbar grey">
                <h2>MyReact</h2>
                <ul>
                    <NavItem items={ this.state.items }/>
                </ul>
            </div>
        );
    };
}

export default Navbar;

NavItem: NavItem:

import React from 'react';

const NavItem = ({ items }) => { 
    const menuItemList = items.map((item) => {
        return (
            <li key={item.id}>
                { item.name }
            </li>
        );
    })
    return (
        <div>
            { menuItemList }
        </div>
    )
}

export default NavItem;

AddNavItem: AddNavItem:

import React, { Component } from 'react';

class AddNavItem extends Component {
    state = {
        id: Math.random(),
        name: null,
        link: null
    }

    handleInput = (e) => {
        this.setState({
            [e.target.id]: e.target.value,
        });
    }

    handleSubmit = (e) => {
        e.preventDefault();
        this.props.addNavItem(this.state);
    }

    render() {
        return (
            <div className="centered flex-column-centered">
                <form onSubmit={ this.handleSubmit }>
                    <h4 className="labelField">Название раздела:</h4>

                    <input 
                        className="inputField" 
                        type="text"
                        id="name" 
                        placeholder="укажите название" 
                        onChange={ this.handleInput } />

                    <h4 className="labelField">URL:</h4>

                    <input
                        className="inputField" 
                        type="text"
                        id="link" 
                        placeholder="укажите ссылку" 
                        onChange={ this.handleInput } />

                    <button className="submitBtn">Добавить</button>
                </form>
            </div>
        );
    }
}

export default AddNavItem;

 let arr = [3,4,5] console.log(arr.unshift(3,5)) 

addNavItem = (item) => {
    let newItems = [...this.state.items];
    newItems.unshift(item)
    this.setState({
            items: newItems
        }
    });
}

Now you are updating the array and adding the elements to the begining of it, which i assume you wanted and is why you picked upshift. 现在,您要更新数组并将元素添加到数组的开头,我认为这是您想要的,这就是您选择升档的原因。 you are then setting the sate equal to the updated array you have. 然后将状态设置为等于您拥有的更新数组。

According to Mozilla docs 根据Mozilla的文档

The unshift() method adds one or more elements to the beginning of an array and returns the new length of the array. unshift()方法将一个或多个元素添加到数组的开头,并返回数组的新长度。

So when you try to change your state using this, it's returning the length of the array instead of the new array you're trying to update the state to. 因此,当您尝试使用此方法更改状态时,它会返回数组的长度,而不是您尝试将状态更新为的新数组。 On top of that, this method is mutable as you are modifying the original array instead of returning a new copy of it. 最重要的是,此方法是可变的,因为您正在修改原始数组,而不是返回它的新副本。 I would suggest changing your code to use the array.prototype.concat() method instead as it keeps your state immutable as it returns a new array instead of modifying the original array. 我建议您更改代码以使用array.prototype.concat()方法代替,因为它可以使您的状态保持不变,因为它返回新数组而不是修改原始数组。

Try changing your method to this instead. 尝试将您的方法更改为此。

addNavItem = (item) => {
    this.setState({ items: this.state.items.concat(item) });
}

Edit: 编辑:

If you are using es6, you can use the spread syntax which also returns a new copy of the array. 如果使用的是es6,则可以使用传播语法 ,该语法还返回数组的新副本。

addNavItem = (item) => {
    this.setState({ items: [...this.state.items, item] });
}

Edit 2: In your Navbar component, you're setting this.props.items to state when it initializes and then you don't update your state when this.props.items change. 编辑2:在Navbar组件中,您将this.props.items设置为在初始化时声明,然后在this.props.items更改时不更新状态。

You don't need state for this component, I would change your NavBar component to look like this: 您不需要此组件的状态,我可以将NavBar组件更改为如下所示:

import React from 'react';
import NavItem from './NavItem';

const Navbar = (props) => {
        return (
            <div className="centered navbar grey">
                <h2>MyReact</h2>
                <ul>
                    <NavItem items={ props.items }/>
                </ul>
            </div>
        );
}

export default Navbar;

Edit 3: 编辑3:

If you want to keep your items inside state in your NavBar component, then you need to watch for updates being made to the items props on that component. 如果要将项目保持在NavBar组件中的内部状态,则需要注意是否对该组件上的item道具进行了更新。

import React, { Component } from 'react';
import NavItem from './NavItem';

class Navbar extends Component {
    state = {
        items: this.props.items,
    }

    componentDidUpdate(prevProps) {
      if (this.props.items!== prevProps.items) {
        this.setState({ items: this.props.items });
      }
    }

    render() {
        return (
            <div className="centered navbar grey">
                <h2>MyReact</h2>
                <ul>
                    <NavItem items={ this.state.items }/>
                </ul>
            </div>
        );
    };
}

export default Navbar;
addNavItem = (item) => {
  this.setState((prevState) => {items: [...prevState.items, item]})
}

This should work. 这应该工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM