Как работают связи state в react js?

Только разбираюсь с реактом и не могу понять как react оперирует state'ом. В данном компоненте рендерится простая табличка с каждой строкой, соответствующей одной node. При нажатии на кнопку edit в одной из строк, соответствующий node копируется в selected_node, и показывается уже другая строка с инпутом, изменяющим selected_node. Но почему-то после изменения при отмене редактирования (cтирании selected_node) измененным оказывается уже первоначальный state.nodes и после нажатия cancel начальная таблица становится изменененной.

Если в кратце - как сделать так, что бы при редактировании одной selected_node не менялся общий state.nodes

import React from 'react';

export default class TestPage extends React.Component {
constructor(props) {
    super(props);

    this.state = {
        nodes: [
            {id: 1, content: "qwerty"},
            {id: 2, content: "abcdef"}
        ],
        selected_node: {}
    };
}
cancelEdit() {
    this.setState({selected_node: {}});
}
selectNode(node) {
    this.setState({selected_node: node});
}
handleContent(event) {
    let selected_node = this.state.selected_node;
    selected_node.content = event.target.value;
    this.setState({selected_node: selected_node});
}
render() {
    let self = this;

    return (
        <div>
            <table>
                <thead>
                    <th>id</th>
                    <th>content</th>
                    <th>edit</th>
                </thead>
                <tbody>
                {this.state.nodes.map(function(node, i) {
                    if(node.id == self.state.selected_node.id) {
                        return <tr key={i}>
                            <td>{node.id}</td>
                            <td><input
                                value={self.state.selected_node.content}
                                onChange={self.handleContent.bind(self)}
                            />
                            </td>
                            <td>
                                <button>save</button>
                                <button onClick={self.cancelEdit.bind(self)}>cancel</button>
                            </td>
                        </tr>
                    } else {
                        return <tr key={i}>
                            <td>{node.id}</td>
                            <td>{node.content}</td>
                            <td><button onClick={self.selectNode.bind(self, node)}>edit</button></td>
                        </tr>;
                    }
                })}
                </tbody>
            </table>
        </div>
    );
}
};
  • Вопрос задан
  • 303 просмотра
Решения вопроса 1
fnnzzz
@fnnzzz
front-end dev
ты в selectNode присваиваешь не содержимое объекта, а ссылку на него и потом по этой ссылке делаешь изменения в объекте.

тобишь если сделать что-то типа того:

selectNode(node) {
	let nodeNew = Object.assign({}, node)
    this.setState({selected_node: nodeNew});
}


то все будет ок, но вообще делать такое совсем не комильфо, передавать сам инстанс в качестве параметра.. в крайнем случае лучше заюзать "ref".

а вообще, здесь можно обойтись и без копирования, просто меняй у самого объекта флажок, вроде "edit" и в зависимости от его значения рендерь, что нужно..

что-то вроде этого:

import React, { Component } from 'react'


export default class TestPage extends Component {
constructor(props) {
    super(props);

    this.input = null
    this.state = {
        nodes: [
            { id: 1, content: "qwerty", edit: false },
            { id: 2, content: "abcdef", edit: false }
        ],
        inputVal: ''
    };
}

toggleEdit(id, isEdit) {
    this.setState({
    	...this.state,
    	nodes: this.state.nodes.map(n => {
    		if( n.id === id ) {
    			n.edit = isEdit
    		}
    		return n
    	})
    })
}  

handleContent(event) {
	....
}

render() {
    return (
        <div>
            <table>
                <thead>
                    <th>id</th>
                    <th>content</th>
                    <th>edit</th>
                </thead>
                <tbody>

                {this.state.nodes.map((node) => {
                    if(node.edit) {
                        return <tr key={node.id}>
                            <td>{node.id}</td>

                            <td><input
                            	onChange={this.handleContent.bind(this)}
                            	ref={(input) => this.input = input}
                                value={this.state.inputVal}
                            />
                            </td>
                            <td>
                                <button type="submit">save</button>
                                <button onClick={() => this.toggleEdit(node.id, false)}>cancel</button>
                            </td>
                        </tr>
                    } else {
                        return <tr key={node.id}>
                            <td>{node.id}</td>
                            <td>{node.content}</td>
                            <td><button onClick={() => this.toggleEdit(node.id, true)}>edit</button></td>
                        </tr>;
                    }
                })}

                </tbody>
            </table>
        </div>
    );
}
};
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы