setState()不更新值

时间:2018-09-21 13:49:44

标签: javascript reactjs

我正在尝试更新组件的状态,但无法正常工作。我有主页容器组件=>嵌套的Navbar容器组件=>嵌套的NavItem UI组件。同样在主页上,我有AddNavItem容器组件,应将项目添加到Navbar。看起来像这样:

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

这是我的主页代码:

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;

问题在于,即使addNavItem被触发后,我也总是得到带有3个初始obj的旧数组。 <Navbar />仍将包含3个元素的数组。我已经阅读了有关异步setState的信息,并按照文档https://reactjs.org/docs/faq-state.html中的描述进行操作。

UPD::我更改了代码(取消移位)以返回数组,而不是数组的长度。控制台日志显示我得到了带有4个obj的新数组

UPD:我所有组件的完整代码:

导航栏

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:

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:

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;

3 个答案:

答案 0 :(得分:0)

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
        }
    });
}

现在,您正在更新数组并将元素添加到数组的开头,我认为这是您想要的,这就是为什么您选择升档。然后将状态设置为与拥有的更新数组相等。

答案 1 :(得分:0)

根据Mozilla docs

  

unshift()方法将一个或多个元素添加到数组的开头,并返回数组的新长度。

因此,当您尝试使用此方法更改状态时,它会返回数组的长度,而不是要尝试将状态更新为的新数组。最重要的是,此方法是 mutable (可变的),因为您正在修改原始数组而不是返回它的新副本。我建议更改您的代码以使用array.prototype.concat()方法,因为它使状态保持不可变,因为它返回一个新数组而不是修改原始数组。

尝试将您的方法更改为此。

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

编辑:

如果您使用的是es6,则可以使用spread syntax,它还会返回该数组的新副本。

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

修改2: 在Navbar组件中,您将this.props.items设置为在初始化时声明,然后在this.props.items更改时不更新状态。

您不需要此组件的状态,我将更改您的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;

修改3:

如果要将项目保持在NavBar组件的内部状态,则需要注意是否对该组件上的道具进行了更新。

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;

答案 2 :(得分:0)

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

这应该有效。