反应访问并在渲染之外更新变量

时间:2018-07-31 13:18:52

标签: javascript reactjs

我目前正在学习React,并且正在关注guy Youtube Videos

但是,它们已经过时了,很难与旧的代码相处。我已经尝试了一些Stackoverflow和Google解决方案,但是它们没有帮助。

现在我在如何访问在todo内声明的变量render()并在handleDelete之外使用我的函数render()更新变量的问题上呢? / p>

我的目标是删除我单击的项目。

我已经尝试在构造函数()中设置变量,但是无法为它赋予this.props.todos的值。

我的代码:

import React from 'react';
import ReactDom from 'react-dom';

export default class TodoItem extends React.Component {

  handleDelete(item){
    let updatedTodos = this.props.todos;
    updatedTodos = updatedTodos.filter((val,index) => {
      return item !== val;
    })
    todos = updatedTodos;
  };

  render() {
    //Add all this.props items
    let todos = this.props.todos;
    todos = todos.map((item, index) => {

      return (
      <li>
        <div className="todo-item">
          <span className="item-name">{item}</span>
          <span className="item-remove" onClick={this.handleDelete.bind(this, item)}> x </span>
        </div>
      </li>);
    });


    return (<React.Fragment>{todos}</React.Fragment>)
  };
}

(此代码后来导出到index.js中,并在其中使用Babel进行编译)

感谢您抽出宝贵的时间!

更新

这里是index.js

import React from 'react';
import ReactDom from 'react-dom';
import TodoItem from './todoItem'; 

class TodoComponent extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        todos: ["clean up", "walk doggo", "take nap"]
      };
    }
    render() {

      return (<div>

        <h1>The todo list:</h1>
        <ul>
          <TodoItem todos={this.state.todos}/>
        </ul>
      </div>);
    }

  }

  ReactDom.render(<TodoComponent/>, document.querySelector(".todo-wrapper"));

3 个答案:

答案 0 :(得分:3)

TodoComponent

import React from 'react';
import ReactDom from 'react-dom';
import TodoItem from './todoItem'; 

class TodoComponent extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        todos: ["clean up", "walk doggo", "take nap"]
      };
    }
    handleDelete(item){
        let todos = this.state.todos;
        todos= todos.filter((todo) => todo !== item);
        this.setState((prevState) => ({
            todos: todos
        }));
    };
    render() {

      return (<div>

        <h1>The todo list:</h1>
        <ul>
          <TodoItem todos={this.state.todos} handleDelete={this.handleDelete}/>
        </ul>
      </div>);
    }

  }

  ReactDom.render(<TodoComponent/>, document.querySelector(".todo-wrapper"));

Todo物品

import React from 'react';
import ReactDom from 'react-dom';

export default class TodoItem extends React.Component {
    render() {
        return ( 
            this.props.todos.map((item) => {
            return (
                <li>
                    <div className="todo-item">
                    <span className="item-name">{item}</span>
                    <span className="item-remove" onClick={() => this.props.handleDelete(item)}> x </span>
                    </div>
                </li>
            )
        }))
    }
}

您的代码在TodoItem中出现问题,您试图删除TodoItem中无法访问状态的项目。而且,如果您在组件中执行某些操作,并且想要使更改反映出来,则必须重新渲染组件。当您的状态更改时,这是可能的。与相应更改相关的组件将重新呈现自己

答案 1 :(得分:1)

我没有测试过,所以可能会有一些错别字,但是您必须这样做

import React from 'react';
import ReactDom from 'react-dom';

export default class TodoItem extends React.Component {

handleDelete(item){
   this.props.updateTodos(item)
};

render() {
//Add all this.props items
 let todos = this.props.todos;
 todos = todos.map((item, index) => {

  return (
  <li>
    <div className="todo-item">
      <span className="item-name">{item}</span>
      <span className="item-remove" onClick={this.handleDelete.bind(this, item)}> x </span>
    </div>
  </li>);
 });


 return (<React.Fragment>{todos}</React.Fragment>)
};
}



import React from 'react';
import ReactDom from 'react-dom';
import TodoItem from './todoItem'; 

class TodoComponent extends React.Component {
constructor(props) {
  super(props);
  this.state = {
    todos: ["clean up", "walk doggo", "take nap"]
  };
  this.updateTodos =this.updateTodos.bind(this);
}
 updateTodos(item){
   this.setState({todos :this.state.todos.filter((val,index) => {
     return item !== val;
   })})
}
render() {

  return (<div>

    <h1>The todo list:</h1>
    <ul>
      <TodoItem todos={this.state.todos} updateTodos ={this.updateTodos}/>
    </ul>
  </div>);
}

}

 ReactDom.render(<TodoComponent/>, document.querySelector(".todo-wrapper"));

答案 2 :(得分:1)

我为您建议另一种方法。您需要更好地思考一些问题。首先,建议您将todo作为对象,并让它们具有idtext属性。

第二,您有一个单独的组件,但您将整个todos传递给它。取而代之的是,映射您的todos,然后将每个todo传递给您的组件。这样,您对一切的管理将变得更加容易。

根据您的情况,您需要一个删除处理程序来传递您的TodoItem,然后使用该处理程序来执行操作。

最后,您的TodoItem不必是一个类组件,因此我已对其进行了更改。

这是一个可行的示例。我已根据我的建议更改了您的代码。

class Todos extends React.Component {
  state = {
    todos: [
      { id: 1, text: "foo" },
      { id: 2, text: "bar" },
      { id: 3, text: "baz" },
    ]
  }

  deleteTodo = ( todo ) => {
    const newTodos = this.state.todos.filter( el => el.id !== todo.id );
    this.setState({ todos: newTodos });
  }

  render() {
    const { todos } = this.state;
    return (
      <div>
        <ul>
        {
          todos.map( todo => <TodoItem key={todo.id} todo={todo} deleteTodo={this.deleteTodo} /> )
        }
        </ul>
      </div>
    )
  }
}

const TodoItem = props => {
  const handleDelete = () => props.deleteTodo(props.todo);

  return (
    <li onClick={handleDelete}>{props.todo.text} x</li>
  )
};

ReactDOM.render(<Todos />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

此外,昨晚我为另一个问题写了一个小例子。但是它越来越大,我没有发布。但是,这是一个简单的小型Todo示例。当然必须进行一些改进,但是您可以作为示例进行研究。

https://codesandbox.io/s/01v3kmp9vv

修改

如果您不想使用class-fields并安装另一个Babel插件,只需使用以下内容更改相关部分:

class Todos extends React.Component {
  consturctor( props ) {
      super( props );
      this.state = {
          todos: [
          { id: 1, text: "foo" },
          { id: 2, text: "bar" },
          { id: 3, text: "baz" },
        ],
  }
}
....rest of the code